Extending IRepository

15 views
Skip to first unread message

Paul Hinett

unread,
Aug 4, 2009, 3:08:14 PM8/4/09
to sharp-arc...@googlegroups.com

Hi Everyone.

 

I’m very new to NHibernate, Fluent & S#arp but i’m very keen to learn and have an idea of how OOP and DDD works.

 

One question I have though is if it’s possible to some way extend the IRepositry class, at the moment it provides some basic CRUD functions such as Get, GetAll etc...

 

However, for this project I am creating for virtually every call to the database i need to pass  a SiteId to filter the data, i thought it would be easier to extend the IRepositroy class itself rather than creating 15-20 interfaces which inherit the IRepository class (like the Northwind example project has done for a couple of classes) and add my own functions.

 

Also, i would like to include a function to page data results, so instead of GetAll, you would have GetAllPaged(pageIndex, numPerPage) so all classes which inherit the IRepositry interface can use these functions.

 

Sorry if any of my terminology is incorrect, hope you understand what i mean!

 

 

Regards,

Paul Hinett

 

w: http://www.ukcreativedesigns.com | e: pa...@ukcreativedesigns.com | t: 07958 552 157

 

Claudio Maccari

unread,
Aug 4, 2009, 4:37:34 PM8/4/09
to sharp-arc...@googlegroups.com
Hi Paul,

I've posted in the past about this topic
Look for IRepository2 in this group

HTH
claudio

2009/8/4 Paul Hinett <pa...@ukcreativedesigns.com>:
--
Claudio Maccari
--------------------------------
http://testdrivendevelopment.wordpress.com/

Simone Busoli

unread,
Aug 5, 2009, 3:28:35 PM8/5/09
to sharp-arc...@googlegroups.com
Hi Paul, if I understand correctly what you're talking about is multi tenancy, with regards to the need of passing a SiteId to every call to the repository. Can you explain further why you need to do so?

About additional methods like GetAllPaged, what about extension methods?

Paul Hinett

unread,
Aug 5, 2009, 6:06:09 PM8/5/09
to sharp-arc...@googlegroups.com

Hi,

 

Thanks for the replies so far, the reason I need to pass SiteId to most calls is because my application will run several versions of the website for multiple domains.

 

At the moment I have 2 domains (house-mixes.com & urban-mixes.com). Both sites work identically but contain it’s own set of members and member data such as music, profiles, messages etc...

 

So when i need to return data from the database such as a list of members, dj mixes, genres etc i need to pass a SiteId to filter the data.

 

Having thought about it a little i may just create my own custom repositories for this data and be done with it, am I right in thinking this?

 

Thank You!

 

Paul

Simone Busoli

unread,
Aug 6, 2009, 3:48:42 AM8/6/09
to sharp-arc...@googlegroups.com
Well, what I was thinking about is that the repository for house-mixes and urban-mixes will certainly have the same public interface, but they will just perform queries supplying an additional parameter (SiteId) with a different value. Therefore why not assign that parameter at the beginning of an operation and have it for free without needing to pass it all along the way? That might be a constructor parameter on the repository, for example.

If you're using Windsor as the container you can do this easily by using handler selectors. You can use the host http header to understand what site the request is coming from, and let windsor instantiate a repository configured for that site.

Pseudo code for a parametric repository:

class Repository
{
  public Repository(int siteId)
  {
     this.siteId = siteId;  
  }

  public IList GetAll()
  {
      return Session.Linq().Where(x => x.siteId == siteId);
  }
}

Mike Hadlow has an example about using handler selectors for doing the same thing: http://mikehadlow.blogspot.com/2008/11/multi-tenancy-part-2-components-and.html

Martin Hornagold

unread,
Aug 6, 2009, 4:48:47 AM8/6/09
to sharp-arc...@googlegroups.com

Is there any data that is shared between the sites.

If not it sounds like you would be better off with separate databases.

Paul Hinett

unread,
Aug 6, 2009, 6:09:09 AM8/6/09
to sharp-arc...@googlegroups.com
Yes the data can be shared. Members can login to either site but once logged in the data is seperate for now...this could change in the future which is why i want to keep it in a single database.

Paul Hinett

unread,
Aug 6, 2009, 6:11:51 AM8/6/09
to sharp-arc...@googlegroups.com
This sounds promising thank you very much...will take a look this evening to see if i can get this working!!

Thanks Simone

Sent from my Nokia phone
-----Original Message-----
From: Simone Busoli
Sent: 06/08/2009 8:48:42 am
Subject: Re: Extending IRepository

Well, what I was thinking about is that the repository for house-mixes and
urban-mixes will certainly have the same public interface, but they
will just perform queries supplying an additional parameter (SiteId) with a
different value. Therefore why not assign that parameter at the beginning of
an operation and have it for free without needing to pass it all along the
way? That might be a constructor parameter on the repository, for example.
If you're using Windsor as the container you can do this easily by using
handler selectors. You can use the host http header to understand what site
the request is coming from, and let windsor instantiate a repository
configured for that site.

Pseudo code for a parametric repository:

class Repository
{
public Repository(int siteId)
{
this.siteId = siteId;
}

public IList GetAll()
{
return Session.Linq().Where(x => x.siteId == siteId);
}
}

Mike Hadlow has an example about using handler selectors for doing the same
thing:
http://mikehadlow.blogspot.com/2008/11/multi-tenancy-part-2-components-and.html

On Thu, Aug 6, 2009 at 00:06, Paul Hinett <pa...@ukcreativedesigns.com>wrote:

> Hi,
>
>
>
> Thanks for the replies so far, the reason I need to pass SiteId to most
> calls is because my application will run several versions of the website for
> multiple domains.
>
>
>
> At the moment I have 2 domains (house-mixes.com & urban-mixes.com). Both
> sites work identically but contain it’s own set of members and member data
> such as music, profiles, messages etc...
>
>
>
> So when i need to return data from the database such as a list of members,
> dj mixes, genres etc i need to pass a SiteId to filter the data.
>
>
>
> Having thought about it a little i may just create my own custom
> repositories for this data and be done with it, am I right in thinking this?
>
>
>
> Thank You!
>
>
>
> Paul
>
>
>
> *From:* sharp-arc...@googlegroups.com [mailto:
> sharp-arc...@googlegroups.com] *On Behalf Of *Simone Busoli
> *Sent:* 05 August 2009 20:29
> *To:* sharp-arc...@googlegroups.com
> *Subject:* Re: Extending IRepository
>
>
>
> Hi Paul, if I understand correctly what you're talking about is multi
> tenancy, with regards to the need of passing a SiteId to every call to the
> repository. Can you explain further why you need to do so?
>
>
>
> About additional methods like GetAllPaged, what about extension methods?
>
> On Tue, Aug 4, 2009 at 21:08, Paul Hinett <pa...@ukcreativedesigns.com>
> wrote:
>
> Hi Everyone.
>
>
>
> I’m very new to NHibernate, Fluent & S#arp but i’m very keen to learn and
> have an idea of how OOP and DDD works.
>
>
>
> One question I have though is if it’s possible to some way extend the
> IRepositry class, at the moment it provides some basic CRUD functions such
> as Get, GetAll etc...
>
>
>
> However, for this project I am creating for virtually every call to the
> database i need to pass a SiteId to filter the data, i thought it would be
> easier to extend the IRepositroy class itself rather than creating 15-20
> interfaces which inherit the IRepository class (like the Northwind example
> project has done for a couple of classes) and add my own functions.
>
>
>
> Also, i would like to include a function to page data results, so instead
> of GetAll, you would have GetAllPaged(pageIndex, numPerPage) so all classes
> which inherit the IRepositry interface can use these functions.
>
>
>
> Sorry if any of my terminology is incorrect, hope you understand what i
> mean!
>
>
>
>
>
> Regards,
>
> Paul Hinett
>
>
>
> *w*: http://www.ukcreativedesigns.com | *e*: pa...@ukcreativedesigns.com |
> *t*: 07958 552 157
>
>
>
>
>
>
>
>
>
>
>
> >
>





Scott Belchak

unread,
Aug 6, 2009, 10:51:31 AM8/6/09
to sharp-arc...@googlegroups.com
I would still consider using seperate databases with a shared database for users.

Bobby Johnson

unread,
Aug 6, 2009, 11:15:18 AM8/6/09
to sharp-arc...@googlegroups.com
Ayede has a great sample multi-tenant application using nhibernate and MVC here. Some slight customizations of S#arp should get you the same effect. Ayede's sample uses query string to differentiate tenants but it would be trivial to use domain or subdomain to get the same effect.
--
"The explanation requiring the fewest assumptions is most likely to be correct."

- Occam’s Razor
http://en.wikipedia.org/wiki/Occam's_Razor

Bobby Johnson

unread,
Aug 6, 2009, 11:19:43 AM8/6/09
to sharp-arc...@googlegroups.com
Oh I forgot to mention that Ayende also has a whole series on multi-tenant architecture with some very sound reasoning and advice. Might want to read up on that as well.

Paul Hinett

unread,
Aug 6, 2009, 11:31:24 AM8/6/09
to sharp-arc...@googlegroups.com

Thank you very much guys, mult-tanant architecture is new terminology to me and is exactly what i am looking for!

 

When you say i may need to make some slight customisations of S#arp, do you mean i will need to modify the S#arp source code?

 

Thanks for all the help on this matter so far!

Bobby Johnson

unread,
Aug 6, 2009, 11:50:14 AM8/6/09
to sharp-arc...@googlegroups.com
Paul,

Currently S#arp allows you to point your repositories to specific databases by way of the SessionFactoryAttribute. You can google around for examples of its use.

You are looking for a more dynamic method of selection like the one used by Ayende. Looking at his code and how SessionFactoryAttribute is used, you should be able to come up with your own implementation of the base Repository class. Heck inherit from it and just override the bits you need.

Feel free to ask more questions as you need to.

Bobby

Paul Hinett

unread,
Aug 6, 2009, 7:18:43 PM8/6/09
to sharp-arc...@googlegroups.com

Hi,

 

I’ve had a good read through lots of information about Multi-Tenancy on the web, Ayende’s articles were very good and offered some very good advice which I want to follow.

 

I have downloaded the sample application created by him, the MultiTenancy.Web application. I think i understand what’s going on here, however I can’t get my head around how I would split this project up into different layers, such as my Core project, data project etc  from the code he has provided, the code is also based around standard NHibernate and doesn’t use multi-tier architecture which is throwing me off understanding.

 

The sample application is using xml configuration files for NH, and includes a Model folder inside the multiple MVC projects for different tenants, obviously this isn’t what i want to do in s#arp.

 

I am probably asking for quite a lot of help in one topic her, but i’m not sure how i can break my questions down?

 

This is probably one of the main files which i am stuck with at the moment:

 

public abstract class AbstractBootStrapper : IBootStrapper

    {

        private IWindsorContainer container;

        public RootContext RootContext { get; private set; }

        public abstract string TenantId { get; }

 

        protected virtual Assembly Assembly

        {

            get { return GetType().Assembly; }

        }

 

        #region IBootStrapper Members

 

        public void Init(RootContext context)

        {

            RootContext = context;

        }

 

        public TenantContext CreateContext()

        {

            container = CreateContainer();

            ConfigureContainer();

            ConfigureNHibernate();

            return new TenantContext(container, Assembly.GetName().Name);

        }

 

        #endregion

 

        protected virtual void ConfigureNHibernate()

        {

            var configuration = new Configuration()

                .SetProperties(new Dictionary<string, string>

                {

                    {Environment.Dialect, typeof (MsSql2005Dialect).AssemblyQualifiedName},

                    {Environment.ProxyFactoryFactoryClass, typeof (ProxyFactoryFactory).AssemblyQualifiedName},

                    {Environment.ConnectionString, RootContext.GetConnectionStringFor(TenantId)},

                });

            var customMapping = GetMappingFrom(Assembly);

            var added = new HashSet<string>();

            foreach (var mapping in customMapping)

            {

                configuration.AddResource(mapping, Assembly);

                added.Add(GetEntityName(mapping));

            }

            var coreMapping = GetMappingFrom(typeof(AbstractBootStrapper).Assembly);

            foreach (var mapping in coreMapping)

            {

                if (added.Add(GetEntityName(mapping)) == false)

                    continue;//already there

                configuration.AddResource(mapping, typeof (AbstractBootStrapper).Assembly);

            }

 

            container.Kernel.AddComponentInstance<Configuration>(configuration);

 

            ISessionFactory sessionFactory = configuration.BuildSessionFactory();

            //wasNHibernateInitialized = true;

           

            var updater = new SchemaUpdate(configuration);

            updater.Execute(false, true);

 

            container.Kernel.AddComponentInstance<ISessionFactory>(sessionFactory);

        }

 

        private string GetEntityName(string mapping)

        {

            var replace = mapping.Replace(".hbm.xml", "");

            var namespaceEnd = replace.IndexOf("Model.");

            return replace.Substring(namespaceEnd);

        }

 

        private static IEnumerable<string> GetMappingFrom(Assembly assembly)

        {

            return from mapping in assembly.GetManifestResourceNames()

                   where mapping.EndsWith(".hbm.xml")

                   select mapping;

        }

 

        protected virtual void ConfigureContainer()

        {

            container.Register(

                AllTypes.Of<IController>()

                    .FromAssembly(Assembly)

                    .Configure(registration =>

                    {

                        var name = registration.Implementation.Name;

                        registration.Named(name.Replace("Controller", "").ToLowerInvariant());

                    }),

 

                 AllTypes.Of<IController>()

                    .FromAssembly(typeof(AbstractBootStrapper).Assembly)

                    .Configure(registration =>

                    {

                        var name = registration.Implementation.Name;

                        registration.Named(name.Replace("Controller", "").ToLowerInvariant());

                    }),

 

                AllTypes.FromAssembly(Assembly)

                    .Where(x=>x.Namespace.EndsWith("Services"))

                    .WithService.FirstInterface(),

 

                AllTypes.FromAssembly(typeof(AbstractBootStrapper).Assembly)

                    .Where(x=>x.Namespace.EndsWith("Services"))

                    .WithService.FirstInterface()

                );

        }

 

        protected virtual WindsorContainer CreateContainer()

        {

            return new WindsorContainer();

        }

    }

 

If anybody has this project downloaded or has any experience with it I would be extremely greatful if you could point me in the right direction, as soon as i have got my claws into it and grasp what is going on I should be fine.

 

Thank you very much!

 

Paul

Paul Hinett

unread,
Aug 7, 2009, 11:32:16 AM8/7/09
to sharp-arc...@googlegroups.com

I have had a good go at looking through various source codes today which deal with Multi-Tenancy and NHibernate but can’t work out what steps to take to achieve my goal with S#arp.

 

This is what i want to achieve:

 

1)      Have a Main website with all the normal S#arp projects (core, data, web etc), this uses it’s own database as normal.

2)      Have other tenant websites which extend the main website the way that Ayende described, i’m assuming i also want other tenant to have their own projects (core, data, web etc which inherit the main websites classes if i want to expand on them).

3)      At the moment in my global.asax i am calling the SchemeUpdate method to make any required changes to the DB, how can I do this to update both databases for both tenants.

 

I am a real newbie when it comes to dependency injection, reflection and S#arp so it’s a big learning curve for me and I think you guys are probably the best to be talking to as you seem extremely helpful!

 

Could someone provide some pseudo code or even a skeleton project which shows how to achieve this? It’s probably asking too much i know but thought i would ask anyway.

 

I have looked at several projects which utilise some of these technologies and I mostly understand them, but they don’t keep each layer separate, such as the models and controllers are all part of the MVC app.

 

Thank you guys!

 

Paul

Bobby Johnson

unread,
Aug 7, 2009, 6:25:12 PM8/7/09
to sharp-arc...@googlegroups.com
Hi Paul,

I was interested in your problem (I used to work on a multi-tenant app so the problem space interests me.) so I did a quick prototype. You can find it here. I'll be whipping up a blog post on it soon explaining all the bits. In the end I didn't have to modify a single file in S#arp.

Enjoy,

Bobby

Paul Hinett

unread,
Aug 7, 2009, 6:43:17 PM8/7/09
to sharp-arc...@googlegroups.com

Hi Bobby,

 

That is fantastic!! I have been working on this all night and this is going to be a HUGE help I can’t thank you enough for your time and help!

 

One question I have though is how can I extend this to support a custom view per tenant and possibly extending the Order Repository per tenant? When reading through Ayende’s blog about this topic he advises to use different projects per tenant and add references to the core project, would this be possible or can it all be done within the same project?

 

Realistically I am only every going to have between 2-10 tenants.

 

Thanks Bobby!

Bobby Johnson

unread,
Aug 7, 2009, 9:16:32 PM8/7/09
to sharp-arc...@googlegroups.com
Hi Paul,

Blog post is up explaining the various items in the project. I am happy to help. If you want to do per tenant views you will need to look into how view engines are implemented in MVC. Take a look at the AreaViewEngine class in S#arp. As for customizable domain entities per tenant, we may have to talk about my billing rates at that point. 8)

Bobby

Paul Hinett

unread,
Aug 10, 2009, 6:39:33 AM8/10/09
to sharp-arc...@googlegroups.com

Hi Bobby,

 

Just thought i would let you know that your  comments aren’t working on your blog, i posted up a comment the other day but just realised it’s not there.

 

Keep up the good work!

Bobby Johnson

unread,
Aug 10, 2009, 10:44:27 AM8/10/09
to sharp-arc...@googlegroups.com
Thanks for the heads up Paul. You are the second person to let me know that posts are failing on my blog. Its time for me to look at switching platforms. But the thought of migrating everything leaves me wonder when I'll have time to get to it. Personal projects always seem to suffer for my time.
Reply all
Reply to author
Forward
0 new messages