Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,970 | Comments: 44,505

filter by tags archive

NHibernateComplex relationships


Originally posted at 11/18/2010

I got an interesting question today (I am teaching my NHibernate course now).

The tabular structure is similar to this:

image

But the desired object structure is:

image

That is quite different than the tabular model, but it is actually very easy to handle this with NHibernate.

Here are the mapping for the Address entity. We use the <join/> tag to have an entity that spans more than a single table:

<class name="Address"
       table="Addresses">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="City" />

  <join table="PeopleAddresses" >
    <key column="AddressId"/>
    <property name="IsDefault"/>
    <property name="ValidFrom"/>
    <property name="ValidTo"/>
  </join>

</class>

We then map the Person, using standard many-to-many mapping for the addresses:

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

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

   <bag name="Addresses" table="PeopleAddresses" inverse="true">
     <key column="PersonId"/>
     <many-to-many class="Address" column="AddressId"/>
   </bag>
   
 </class>

There is just one thing thing to be aware of, you can’t add new addresses via the Person.Addresses collection, because the PeopleAddresses table has more data in it than just the keys. Presumably, you are handling this in some other fashion already.

All in all, this is a pretty elegant solution.

More posts in "NHibernate" series:

  1. (19 Nov 2010) Complex relationships
  2. (27 Jun 2010) Streaming large result sets
  3. (25 May 2009) Why do we need to specify the query type twice?
  4. (20 Mar 2009) Avoid identity generator when possible
  5. (26 Mar 2007) Nullable DateTime Issues
  6. (08 Jan 2007) Fetching multiply collections in one roundtrip

Comments

Victor Kornov

Pardon my ignorance, but how "you can’t add new addresses via the Person.Addresses collection" relates to the conclusion of "this is a pretty elegant solution"? All I can think of is having another set of classes\mappings just to be able to save the person's address. That's not elegant in my books.

Ayende Rahien

Victor,

You need to map the PersonId column on the PeopleAddresses, and then you can threat this as a standard Many To One.

The scenario that was brought up was were there was another way of handling that, so I didn't bother with that

JasonW

The tabular model and the object structure in almost all cases will be quite different, with one modelling data and the other modelling behaviour. This is something that most ORMs don't handle as elegantly as the code above.

Max
Max

What about using <idbag?

Max
Max

Oops, it seems my comment is stripped.

What about using idbag?

Corey

If you really want flexibility given the table structure above and still want to handle inserts.

Create a sql view that fits the exact mapping structure and let the view deal with the inserts appropriately.

Fabio Maulo

Can I refactorize that DB ? or it is untouchable ?

Scooletz

Good, old-fashioned blog entry. Interesting case.

Frans Bouma

I'm with Victor, this isn't elegant at all. It's also wrong: PersonAddresses is an objectified relationship (in Object Role Modeling / NIAM terms), and this means it's an entity by itself. Just because it defines a m:n relationship between person and address doesn't make it an entity which doesn't exist, and the limitation that you can't persist new addresses shows that.

I fail to see why PersonAddresses has to be wiped under the rug: its name is perhaps badly chosen, but it is a valid entity, that you don't want to program with it, is really ignorance: because the entity exists in the domain, you have to deal with it, and which is the reason you have to deal with it too only in 'some other fashion'.

The m:n relationship between person and addresses is readonly, over the objectified relationship. I do recall having a discussion with Fabio about this some time ago on nhusers.

Nestor Rodriguez

This challenge is an evidence of how NHibernate can deal with bad databases design but refactor is a must !.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production postmortem (5):
    29 Jul 2015 - The evil licensing code
  2. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
  3. API Design (7):
    20 Jul 2015 - We’ll let the users sort it out
  4. What is new in RavenDB 3.5 (3):
    15 Jul 2015 - Exploring data in the dark
  5. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats