NHibernate Mapping – Inheritance

I wanted to explore a few options regarding the way we can map inheritance using NHibernate. Here is the model that we are going to use:image

And the code that we are going to execute:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	session.CreateCriteria(typeof(Party)).List();
	session.CreateCriteria(typeof(Company)).List();
	session.CreateCriteria(typeof(Person)).List();
	tx.Commit();
}

From now on we are going to simply play with the mapping options to see what we can come up with. We will start with a very simple discriminator based mapping (table per hierarchy):

<class name="Party"
			 abstract="true"
			 table="Parties">
	<id name="Id">
		<generator class="identity"/>
	</id>
	<discriminator column="Discriminator"
			not-null="true"
			type="System.String"/>

	<subclass
		name="Person"
		discriminator-value="Person">
		<property name="FirstName"/>
	</subclass>

	<subclass
		name="Company"
		discriminator-value="Company">
		<property name="CompanyName"/>
	</subclass>
</class>

Which result in the following table structure:

image

And the SQL that was generated is:

Select Party

image

Select Company

image

Select Person

image

But that is just one option. Let us see what happen if we try the table per concrete class option:

<class name="Person"
	table="People">
	<id name="Id">
		<generator class="identity"/>
	</id>
	<property name="FirstName"/>
</class>

<class name="Company"
	table="Companies">
	<id name="Id">
		<generator class="identity"/>
	</id>
	<property name="CompanyName"/>
</class>

Which result in the following table structure:

image

And the following queries:

Select Party

image

image

No, that is not a mistake, we issue two SQL queries to load all possible parties.

Select Company

image

Select Person

image

The inheritance strategy is table per subclass:

<class name="Party"
		abstract="true"
		table="Parties">
	<id name="Id">
		<generator class="identity"/>
	</id>

	<joined-subclass
		table="People"
		name="Person">
		<key column="PartyId"/>
		<property name="FirstName"/>
	</joined-subclass>

	<joined-subclass
		table="Companies"
		name="Company">
		<key column="PartyId"/>
		<property name="CompanyName"/>
	</joined-subclass>
</class>

Which result in the following table structure:

image

And the queries:

Select Party

image

This is slightly tricky, basically, we get the class based on whatever we have a row in the appropriate table.

Select Company

image

Select Person

image

The final option is using unioned subclasses, which looks like this:

 

<class name="Party"
		abstract="true"
		table="Parties">
	<id name="Id">
		<generator class="hilo"/>
	</id>

	<union-subclass
		table="People"
		name="Person">
		<property name="FirstName"/>
	</union-subclass>

	<union-subclass
		table="Companies"
		name="Company">
		<property name="CompanyName"/>
	</union-subclass>
</class>

Note that it is not possible to use identity with union-subclasses, so I switched to hilo, which is generally much more recommended anyway.

The table structure is similar to what we have seen before:

image

But the querying is drastically different:

Select Party

image

Select Company

image

Select Person

image

The benefit over standard table per concrete class is that in this scenario, we can query over the entire hierarchy in a single query, rather than having to issue separate query per class.

Print | posted on Friday, April 10, 2009 6:43 AM

Feedback


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 8:49 AM HireDotnetexpert

Although these posts are geared towards your COMMERCIAL product, they are very helpful.


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 9:00 AM Ayende Rahien

Hire,
a) please use a real name, not a ad.
b) I don't know if you noticed, but I didn't mention NH Prof in these, and they are talking about basic feature of NH.


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 9:23 AM pcm

As communicated in the email. I am open to delete this comment if it had hurt you. I love what you are doing for the community.

I am also changing my name to acronym. And Also not using a link if that makes you happy.


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 10:18 AM Krzysztof Kozmic

I didn't know about union-subclass. Interesting. There's one thing I think would make a great addition to these posts - insight. Showing the mappings and SQL in a very manual-like way is sure great but I wish you took it one step further and talked about non-obvious strengths and weaknesses of each approach.

Good to see you blogging regularly again :)


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 12:31 PM meo

Did ya read this?

blog.wekeroad.com/.../subsonic-to-acquire-nhibe...


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 2:54 PM alberto

I'm with Krzysztof. It's something I've missed in the series. It feels like some scenarios would help to understand when to use each approach.


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 2:57 PM Tomasz Modelski

@ meo : check the date of this news .... :-)


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 6:31 PM huey

Dumb question. I might have to make a website for our vendors. So it is going to have type user and a user might be an employee or vendor. Both employee / vendor will share the same user table and have unique user id's. This seems to fit in with inheritance mapping in NH.

The thing is, in all cases I'm going to start with a user id and the first thing I'm going to want to do is figure out if the user is an employee or a vendor. So it might be something like:

User user = session.get(userID);
if(user.discriminator == "vendor")
{
vendor = session.get(user.ID);
}
else
{
employee = session.get(user.ID);
}

I feel like I'm missing the whole point / benefit of NH inheritance mapping.

Any suggestions?


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 7:44 PM justin

@huey

Polymorphism is your friend.
User user = session.Get(userId);
Vendor vendor = user as Vendor;
Employee employee = user as Employee;

Lookup the "as" and "is" keywords and also remember you can do explicit casting Vendor vendor = (Vendor)user;


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 8:17 PM Dmitry

I did not know about the union class either.

I do not think it has mentioned that you can use common base classes or interfaces to do polymorphic queries.

So commands like

session.CreateCriteria(typeof(object)).List()
or
session.CreateCriteria(typeof(IEntity)).List() (assuming it's a common interface for the entities)

are legal in NHibernate.


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 8:24 PM David

@alberto and @Krzysztof
from my limited understanding.
table per concrete class - fastest, harder to do polymorphing, bad thing you have to update all the tables if there is a change at the parent class level.

table per hierarchy - fast, but your columns cannot must allow nulls (as multiple classes will not use them), easy for reports.

table per subclass - this is meant to be the slowest (for large projects), I have no proof, but it the best way for normalisation, clean data. So the design looks nicer.

the books i would reconmend
NHibernate in Action, this has a section on this.
Patterns of Enterprise Application Architecture

Also thank you Ayende for doing these posts.. I am finding them great for reference!


Gravatar

# re: NHibernate Mapping – Inheritance 4/10/2009 9:00 PM Trent Foley

It seems to me that 95% of the time you would want to use the first method mentioned (Table per Hierarchy). This has been the approach I have taken to date, and has been painless so far. The other 5% of the time I imagine would be due to having to map to an existing database, or you are working with a DBA who is a Normilazation Nazi.


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 8:11 AM huey

@justin

Thanks, I'm stupid and glossed over the fact that session.get(userID) was grabbing all of the potential data for employee and vendor so I could later cast appropriately.


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 11:12 AM Ayende Rahien

alberto & Krzysztof,
It is a matter of time and place, actually.
Those posts are part of the prep work for the NH course that I am about to give in May.
They represent about 3 hours of discussion of scenarios, alternatives and motives. Pretty hard to put into words by typing them.
And most of the info is already out there.


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 11:13 AM Ayende Rahien

Trent,
There are different optimizations and constraints that apply to each of those.
See David's comments for some of them.


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 12:33 PM sebastijanp

Why is hilo generator "generally much more recommended anyway"? Does it has to do with optimization? What are the benefits over the identity?


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 12:39 PM Ayende Rahien

sebastijan,
HiLo can generate a unique ID without having to go to the database.
It has all the benefits of GUIDs, but without having to deal with the GUID opaque nature.


Gravatar

# re: NHibernate Mapping – Inheritance 4/11/2009 4:37 PM Krzysztof Kozmic

I see,
I've read in few places discussion on pros and cons of each approach. However, I think you, as someone who knows NHibernate in and out, could give a much better and in-depth explanation of the topic.

Maybe some other time then.


Gravatar

# re: NHibernate Mapping – Inheritance 5/5/2009 3:07 AM Chris Nicola

Can the Unioned-Subclass (or any other approach) be applied to interface classes instead of abstract classes? If I have two tables which map to classes that implement the same interface can I setup something where I can get all the objects from both classes with one query on the interface class?


Gravatar

# re: NHibernate Mapping – Inheritance 5/5/2009 8:47 AM Ayende Rahien

Chris,
On the face of it, I don't see why no.


Gravatar

# re: NHibernate Mapping – Inheritance 6/5/2009 6:34 AM dave

Hi,

I am doing "table per subclass" with this exact same DB schema, However I also have a related table called Address which links to Party

The XML mapping file will not allow me to use both joined-subclass for my Company and Invervidual. When I try to include my address into Party via join. Is there any way around this? (p.s I am only new to nHiberbate)

for example
--------------------------
abstract="true"
table="Parties">









...... rest of mapping removed for brevity






--------------------------
Visial stiduo compains when both joined-subclass and join table are entered I can only do one of the other?

TIA Dave


Gravatar

# re: NHibernate Mapping – Inheritance 6/5/2009 6:38 AM dave

Sorry the code should have been like this. (it seems the commect are accepting my less then tags and parsing them as HTML do I smell XSS attacks)

<class name="Party"
abstract="true"
table="Parties">
<id name="Id">
<generator class="identity"/>
</id>
<property name="EntityName" column="entity_name"/>
<property name="ShortName" column="short_name"/>

<join table="logical_address">
<key column="address_id"/>
<component name="ContactDetails" class="ContactDetails">
<property name="EmailAddress" column="email_address"/>
<property name="HomePhone" column="home_phone_number"/>


</component>
</join>


<joined-subclass table="individual" name="Individual">
<key column="party_key"/>


Gravatar

# re: NHibernate Mapping – Inheritance 6/5/2009 4:30 PM Ayende Rahien


Dave,
Please post the full details to nhusers

Comments have been closed on this topic.