Multi Table Entities in NHibernate

time to read 14 min | 2749 words

A while ago I posted about the ability to map n tables to a single entity in the Entity Framework. I didn't like it then, and I quoted from the Hibernate documentation that discourage this behavior:

We consider it an essential element of good object model design that the object model be at least as granular as the relational model. If the original data modeller decided that certain columns should be split across two different tables, then there must have been some kind of conceptual justification for that. There is no reason not to also make that distinction in the object model.

I still believe that this statement is true, except... I just run into an issue with my model, I have a case where I am importing data from another database, and I need to add additional data to it. I could add additional columns to the primary table, but that would make the import process much more complex than I would like it to be. I would have liked to make it work by splitting the data by table, rather than by columns.

With that in mind, I headed to NHibernate's JIRA, and found this issue about the problem. Conveniently, a patch was supplied as well.

A big thanks for Karl Chu for making all the work of porting the functionality from Hibernate. I love Open Source.

At any rate, you can now map several tables into a single entity in NHibernate, you can get the full details here (the new tests), but let us walk through a simple one first.

(Image from clipboard).png 

Name and sex are defined in the Person table, but everything else is defined on the Address table, we map it like this:

<class name="Person">

       <id name="Id" column="person_id" unsaved-value="0">

              <generator class="native"/>

       </id>

 

       <property name="Name"/>

       <property name="Sex"/>

 

       <join table="address">

              <key column="address_id"/>

              <property name="Address"/>

              <property name="Zip"/>

              <property name="Country"/>

              <property name="HomePhone"/>

              <property name="BusinessPhone"/>

       </join>

</class>

Obviously address_id is a FK to person_id (not the best names for them, come to think about it). Trying to load a person would cause this SQL query (reformatted):

SELECT

     p.person_id,

     p.Name,

     p.Sex,

     a.Address,

     a.Zip,

     a.Country,

     a.HomePhone,

     a.BusinessPhone

FROM dbo.Person p inner join dbo.Address a

     on p.person_id=a.address_id

There is quite a bit more that it can do (optional joins, etc), and you can check it out at the tests.

Note: this is on NHibernate trunk, so it won't be in the 1.2 release, which is currently in feature-freeze.