In the last two years we saw many developers becoming from “DataSet world” to “ORM world” (thanks to Microsoft and it’s EntityFramework).
One of the most important challenge of ORM is the abstraction of your domain (entity classes of your business) from its persistent representation (tables in the DB).
To understand how NHibernate solve the ORM challenge I want start from an existing domain. The domain of this post:
public abstract class Animal
{
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
}
public class Reptile: Animal
{
public virtual float BodyTemperature { get; set; }
}
public class Human : Animal
{
public virtual string Name { get; set; }
public virtual string NickName { get; set; }
public virtual DateTime Birthdate { get; set; }
}
public class Family<T> where T: Animal
{
public virtual int Id { get; private set; }
public virtual T Father { get; set; }
public virtual T Mother { get; set; }
public virtual ISet<T> Childs { get; set; }
}
The mapping of the previous post represent the domain in five tables:
Without touch my previous domain, and my previous test, I want represent it in two tables:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="EntityNameInAction"
namespace="EntityNameInAction"
default-access="backfield">
<class name="Animal" abstract="true">
<id name="Id">
<generator class="hilo"/>
</id>
<discriminator column="kind"/>
<property name="Description"/>
<subclass name="Reptile">
<property name="BodyTemperature"/>
</subclass>
<subclass name="Human">
<property name="Name"/>
<property name="NickName"/>
<property name="Birthdate" type="Date"/>
</subclass>
</class>
<class name="Family`1[[Reptile]]" entity-name="ReptilesFamily"
table="Families" discriminator-value="Reptile" where="familyKind = 'Reptile'">
<id name="Id">
<generator class="hilo"/>
</id>
<discriminator column="familyKind"/>
<many-to-one name="Father" class="Reptile" cascade="all"/>
<many-to-one name="Mother" class="Reptile" cascade="all"/>
<set name="Childs" generic="true" cascade="all">
<key column="familyId"/>
<one-to-many class="Reptile"/>
</set>
</class>
<class name="Family`1[[Human]]" entity-name="HumanFamily"
table="Families" discriminator-value="Human" where="familyKind = 'Human'">
<id name="Id">
<generator class="hilo"/>
</id>
<discriminator column="familyKind"/>
<many-to-one name="Father" class="Human" cascade="all"/>
<many-to-one name="Mother" class="Human" cascade="all"/>
<set name="Childs" generic="true" cascade="all">
<key column="familyId"/>
<one-to-many class="Human"/>
</set>
</class>
</hibernate-mapping>
The difference in the Animal hierarchy mapping is trivial and well known by NH users. What is more interesting is the work to persist Family<T> classes. Because I’m using the same table (Families) I need something to discriminate the tow concrete types Family<Reptile> and Family<Human>. In this case I can’t say that Family<Reptile> is a subclass of something else (in my domain I don’t have a superclass for Family<T>) by the way I can use a simple trick. The use of <discriminator>, discriminator-value and where tags is the trick.
Goal achived by NH: same domain, same test, two different persistent representations.
Code available here.
This comment has been removed by a blog administrator.
ReplyDelete