views:

289

answers:

2

So, we're building a multi-tenant system to run as a service. We're starting from the ground up. We're following DDD; the domain has (at the moment) ~20 entities in it, and later there will be more. It is to be hosted by us, geographically redundant (n+1 of everything except SQL queries ;-) ), and of flexible design (well, that last is our own requirement, not the business', though they want us to be able to change it easily on demand of course). We're .NET based, and will be using a relational database for our backing store. We're not against using open-source tools and libraries (at all).

One of the must-have features from the business is that certain entities be extensible by the tenants of the system. For example, client A may want entity Foo to have Title and Abstract properties, whereas client B may want entity Foo to have Publish Date and Directed-By properties - and not Title Abstract.

It may also be the case that it should support data in multiple languages for tenants that want this - for example, one tenant may be interested in translating their whole account into two (or more) languages; both the "static" strings, and the strings attached to the entities as data.

So. Arbitrary number of fields (on top of some common baseline; there are certain things about these entities that all tenants will get), definable by the client (where they can define the data-type too). Possibility of translation of the data (without duplicating the entities - as in, without setting up one set in English, and then setting up the same set in French). Strongly typed, searchable, queryable backing storage, too (so, no extra-stuff-goes-in-an-XML-field, unless there's a way for it to come out strongly-typed and searchable). Performant (but as a secondary requirement; the feature is important enough to buy hardware for if necessary).

Data volumes? In our current system, an "average" client has hundreds of entities, a "big" client has thousands of entities. Requests will usually filter those lists for display to between 10-200ish, and the most common thing to want to do will involve maybe half-a-dozen entities (that in the new system, should be extensible).

Other points? Each Entity has a direct link to the tenant that owns it.

How does one go about this, in .NET-land? It's been suggested that we chuck our entities into an IoC container, and glob them together on the fly at run-time - but how does one map that to a relational database?

I also remember reading Ayende's post on this with Lucene.NET from some significant time ago that sounds good, but we haven't got any experience with Lucene.NET or nHibernate at present. (We're currently going to use Linq2Sql for our ORM but if we need to change that to support this, I'd personally be happy, frankly).

I read this Castle dev list thread which is linked from Ayende, and it seems like nHibernate has something called an IUserType that might help - I wonder whether we might apply that, pulling the appropriate one our of IoC for each tenant? So one IUserType per tenant per extensible-entity, and store the data itself in an XML column inside of SQL Server (our most likely RDBMS).

Lastly, I've just read one suggestion around dynamically changing a DB-table per entity per tenant - but this sounds pretty... Fraught, honestly! I mean, it could work, but it sounds like not such a great idea to give out the ability to do this to tenants (who may be less than tech-savvy). I suppose it could restricted to administrator-employees only...

+1  A: 

Take a look at Ayende's series of posts about multi-tenancy. He analyzes several approaches to the issue of extensibility.

Mauricio Scheffer
A: 

There are a variety of ways to accomplish it, but the issues of multi-tenancy go deeper than just the data model. I hate to be plugging product, but check out SaaSGrid by my the company I work at, Apprenda.We're a cloud operating system that allows you to write single tenant SOA apps (feel free to use NHibernate for data access) that automatically injects multi-tenancy into your app. When you publish your app, you can do things like choose a data model (isolated database or shared) and SaaSGrid will deploy accordingly and your app will run without any code changes - just write code as if it were for a single tenant!