A couple of monthgs ago Ayende talked a lot about multi-tenant applications. In fact he explained my team how we could build such an application. The only thing lacking in Ayende's series of post was some real world examples. Let me try to fill that gap here. It is probably going to be a series of posts since we need to cover a couple of different issues here.
The plan is to add multi-tenancy to the WinecellarManager because then I don't have to start from scratch. For now I have the following posts in mind:
- How to deal with database customization: e.g. a tenant wants a new column in a given table.
- How to deal with differences in business logic?
- How to deal with differences in UI?
I don't know when I will be able to get these posts out but let's start with the first one. In this post we will deal with customizations of the domain model. Ayende dealt with it here. In our project we chose for a solution that the customization needs to be done by a developer because in the end we still want a rich domain model that does not kill you when you have to create reports on top of it. That's why we have a core domain model and tenants can have additions to the core.
It turns out that NHibernate is an excellent choice if you want to build multi tenant applications. In a previous post I already demonstrated one possibility. It is possible to override a complete mapping for a certain entity.
I'll demonstrate another possibility in this post. For one of my fake tenants I need to to have the possibility to keep a score for a wine. I'll start from the mapping for "Wines" and I added a discriminator to that mapping. It now looks like this:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <hibernate-mapping auto-import="false" default-lazy="false" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:nhibernate-mapping-2.2">
3: <class name="WineCellar.Business.Entities.Wine, WineCellar.Business" table="Wines" schema="dbo">
4: <id name="Id" access="property" column="Id" type="System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
5: <generator class="identity">
6: </generator>
7: </id>
8: <discriminator column="Discriminator" type="string" not-null="true"/>
type="string" not-null="true"/>
iscriminator" type="string" not-null="true"/>
9: <property name="Name" access="property">
10: <column name="Name" not-null="true"/>
11: </property>
12: <property name="Producer" access="property">
13: <column name="Producer"/>
14: </property>
15: <property name="Appelation" access="property">
16: <column name="Appelation"/>
17: </property>
18: <property name="ColorType" access="property" >
19: <column name="ColorType"/>
20: </property>
21: <property name="DateAdded" access="property">
22: <column name="DateAdded"/>
23: </property>
24: <property name="SecurityKey" access="property" type="System.Guid">
25: <column name="SecurityKey" not-null="true"></column>
26: </property>
27: <many-to-one name="Region" access="property" class="WineCellar.Business.Entities.Region, WineCellar.Business" column="RegionId" not-null="true" />
28: <many-to-one name="AddedBy" access="property" class="WineCellar.Business.Entities.User, WineCellar.Business" column="UserAdded" not-null="true" />
29: <set name="Raisins" access="property" table="Raisins2Wines" lazy="true">
30: <key column="WineId" />
31: <many-to-many class="WineCellar.Business.Entities.Raisin, WineCellar.Business" column="RaisinId"/>
32: </set>
33: </class>
34: </hibernate-mapping>
Then I created a new class ParkerWine that looks like this:
1: public class ParkerWine :Wine
2: {
3: public virtual int Score { get; set; }
4: }
The mapping for the ParkerWine class:
1: <?xml version="1.0" encoding="utf-8" ?>
2:
3: <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
4: assembly="Parker.Business"
5: namespace="Parker.Business">
6: <subclass name="ParkerWine" extends="WineCellar.Business.Entities.Wine, WineCellar.Business" discriminator-value="Parker">
7: <property name="Score" not-null="true"/>
8: </subclass>
9: </hibernate-mapping>
There is nothing more to it. You define ParkerWine as a "subclass" and tell NHibernate that it extends "Wine". Then you add the extra properties you need and you're done. Once you have done that you can start using ParkerWine in your app. I've created a very small demo console application that you can find here.

1 comment:
live119|live119論壇|
角色扮演|跳蛋|情趣跳蛋|煙火批發|煙火|情趣用品|SM|
按摩棒|電動按摩棒|飛機杯|自慰套|自慰套|情趣內衣|
潤滑液|內衣|性感內衣|自慰器|
充氣娃娃|AV|情趣|衣蝶|
G點|性感丁字褲|吊帶襪|丁字褲|無線跳蛋|性感睡衣|
Post a Comment