Ayende @ Rahien

Refunds available at head office

NHibernate Mapping -

We have previously explored the one-to-one mapping, which let you create 1:1 association in the database, but there is actually another way to map several tables to an object model. We aren’t constrained by the database model, and we can merge several tables into a single entity.

We do that using the <join/> element:

<join
        table="tablename"                        (1)
        schema="owner"                           (2)
        catalog="catalog"                        (3)
        fetch="join|select"                      (4)
        inverse="true|false"                     (5)
        optional="true|false">                   (6)

        <key ... />

        <property ... />
        ...
</join>

Let us explore this a bit, assuming the we have the following database model:"

image

And what we want is to map this to the following object model:

image

We can do this will the following mapping:

<class name="Person"
	 table="People">

	<id name="Id">
		<generator class="identity"/>
	</id>
	<property name="Name" />

	<join table="Addresses">
		<key column="PersonId"/>
		<property name="Line1"/>
		<property name="Line2"/>
		<property name="City"/>
		<property name="Country"/>
		<property name="ZipCode"/>
	</join>
</class>

And getting a Person will now result in the following SQL:

image

NHibernate will now take care of mapping everything to its place, and making sure that everything works just right.

By now you should be able to figure out what fetch means, and inverse should also be familiar. Optional is interesting, what is basically says is that we should always use an outer join to get the values from the Addresses table and if all the mapped properties are null, it wouldn’t create a new row in the Addresses table.

On the face of it, it looks like a nice way to merge tables together, but that isn’t actually the primary reason for this feature. You can use it for that, for sure, but that is mostly useful in legacy databases. In most cases, your object model should be more granular than the database model, not the other way around.

The really interesting part about this feature is that it allows us to mix & match inheritance strategies. It let us create a table per hierarchy that store all the extra fields on another table, for example. That significantly reduce the disadvantage of using a table per hierarchy or table per subclass, since we can tell very easily what is the type of the class that we are using, and act appropriately.

Comments

Evgeny Shapiro
04/20/2009 03:00 AM by
Evgeny Shapiro

It let us create a =table per hierarchy= that store all the extra fields on another table, for example. That significantly reduce the disadvantage of using a =table per hierarchy= or table per subclass...

There's a typo.

Beside this, the post series is awesome :).

Jan Van Ryswyck
04/20/2009 07:49 AM by
Jan Van Ryswyck

The mix & match inheritance strategy you mentioned, is it something like this?

knol.google.com/.../11#8(2E)1(2E)3(2E)(C2)(A0)Tablepersubclass(2C)_usingadiscriminator

Thx

PS: I'm learning a lot from this article series. Thx for spreading the knowledge.

Ayende Rahien
04/20/2009 08:10 AM by
Ayende Rahien

Evgeny,

I don't see the typo

Ayende Rahien
04/20/2009 08:16 AM by
Ayende Rahien

Jan,

Yes, that is what I meant.

Remmus
04/20/2009 08:50 AM by
Remmus

Great series of posts.

tolly
04/20/2009 02:30 PM by
tolly

In the post about {dynamic-component/} i've asked about the way to store key-value pair in detail-table. ayende.com/.../...pping-ltdynamic-componentgt.aspx

I'd like to solve inhertance problem using this key-value princniple. see picture: tweakers.net/.../full.jpg

I want that NHibernate dynamically creates subclasses' attributes using detail-table with key-value pair, where key is the name of the attribute and the value is the value.

Is it possible with NHibernate?

I prefer this solution over the standard ones (like table-per-subclas or table-per-concrete-class), because i have more than 80 subclasses with three hierarchical levels and all with their specific attributes.

Thanks in advance

Ayende Rahien
04/21/2009 07:38 AM by
Ayende Rahien

tolly,

Please follow this up in the mailing list

tolly
04/21/2009 08:26 AM by
tolly

Thanks, Ayende :) Hopely, I'll find the way.

It's a greate blog, i've learnt a lot of new things about NHibernate, thanks

scotty
04/30/2009 02:26 PM by
scotty
Guys,
  
  
We're trying to use the 
<join condition in a table that has a composite primary key.  Outwith the composite key in that table we have another field which is used as a foreign key onto a lookup table.
  
  
Nhibernate complains with the classic 'Foreign key does not have the same number of columns as primary key...' error, when using the 
<join onto the lookup table.
  
  
We've even taken off the foreign key and tried this, but it looks like Nhibernate is dynamically creating a foreign key at runtime, and throwing the error.
  
  
All we're doing is effectively an inner join onto a lookup table, from a table with a composite primary key.
  
  
Any ideas?
  
  
We know creating a surrogate key will solve this, but we're loathe to go down that route.
  
  
thanks.
>
Ayende Rahien
04/30/2009 04:25 PM by
Ayende Rahien

Scotty,

NH isn't trying to generate the FK on the fly, it is complaining because you have an invalid definition. You must have the same number of columns on both.

Comments have been closed on this topic.