NHibernate Part 3: Mapping techniques for aggregation – One To One mapping

Updated code available for NHibernate 2.0.1.GA here.
The toolingset used is Visual Studio 2008 and Sql Server 2008

I finally got to writing my next post on NHibernate. I will be discussing Aggregation. I’m not an expert on NHibernate mapping but have done some experimentation in preparation for a project I’m working on and this post reflects my experiences during this experiments. If you should find any errors or know of other best practices, please let me know so that I can correct them.

But first, let me introduce to you the basic application that we will continue to use in the rest of this series.

The Base Application

Until now we basically had the following steps to do when writing our application:

  • Create a NHibernate configuration object
  • Set the parameters for the configuration object
  • Build a session factory from this configuration object.
  • Create a session with the factory
  • [Optionally] Start a transaction
  • Do your stuff
  • [Optionally] Commit the transaction
  • Close the session

Because only the “Do your stuff” line will change for each demo application, I will put the rest in a base application, which I can then copy to start each demo application. It will also make it easier for you to follow because all the “wiring” stuff will not interfere with the actual code under demonstration.

In the mean while, I will also discuss another feature of NHibernate: logging.

NHibernate uses the apache project log4net as a logging framework. In the base application you can find an example of a logging configuration.

log4net

The basic workings of log4net are as follows:

  • Setup an appender. With this you define how the logging will happen. There are appenders available for logging to the console window, to a file, etc… You can also define the layout of a logging entry. For a more thorough explanation of this syntax look at the log4net SDK documentation for the class PatternLayout.
  • Setup the logging itself. To enable the logging you must specify a logger and refer to the appenders above. Then those appenders are used to write the log messages to their destination.

Note

If you look in the NHibernate documentation for enabling logging you will find that from version 1.0 RC1 of NHibernate the logging should be enabled manually. To my surprise I didn’t have to do this. Just configuring the logger in your applications configuration file and it will work.

You can download a sample base application here.

Now we will get on with the stuff we really are interested in: modeling aggregation with NHibernate.

Multiplicity of aggregation: One to One mapping

The Code

There are three ways to do a one-to-one mapping: using the <one-to-one> mapping tag, using the <many-to-one> mapping tag or using the <component> mapping tag.

Using the <one-to-one> mapping tag

To make a one to one mapping using this tag requires that the primary keys identifying the parent and child record in their respective tables are the same. To achieve this you must do the following:

We have two classes which we want to associate in a parent-child relationship. The parent class is the UPerson class and the child class is the UAddress class.

On the code side:

// The child class
public class UAddress 
{ 
   // More members here, see sample code 
}                   

// The parent class
public class UPerson 
{ 
   // More members here, see sample code 
   public UAddress WhereAbouts 
   { 
      get { return this.address; } 
      set { this.address = value; } 
   } 
}

On the mapping side:

On the mapping side we must somehow associate the id’s of both classes with each other. This is done by referencing in the mapping file of the parent class the id of the child class. So in the mapping file for the UPerson class we write:

<id name="Id" column="Id"> 
   <generator class="foreign">
      <param name="property">
         WhereAbouts
      </param>
   </generator> 
</id> 
<property name="Name"/>
<one-to-one name="WhereAbouts"
         class="UniDirectional.People.UAddress, 
         NHibernateOneToOne"/>


What we are saying inside the <id> node is: Use as id for objects of this class (node <id>) the foreign id (node <generator class=”foreign”>) generated for the object referenced by the property “WhereAbouts” (node <param name=”property”>WhereAbouts</param>).
Inside the <one-to-one> node we are saying that we have a property of type UniDirectional.People.UAddress and with the name “WhereAbouts”.

The mapping file for the UAddress class needs no special tags.

Note

I suppose you could look at the <one-to-one> tag as a type of <property> tag for user defined classes. This is also shown by the use of the name of the one-to-one association in the property parameter of the id-generator.

On the database side:

On the database side setup the parent table to have an id field with a simple integer value, not an autonumber. The child table should have an identity field which is an integer autonumber.

CREATE TABLE `address` (
   `Id` int(10) unsigned NOT NULL auto_increment,
   `Street` varchar(45) NOT NULL default '',
   PRIMARY KEY  (`Id`)
);

CREATE TABLE `person` (
   `Id` int(10) unsigned NOT NULL default '0',
   `Name` varchar(45) NOT NULL default '',
   PRIMARY KEY  (`Id`),
   CONSTRAINT `FK_address` 
      FOREIGN KEY (`Id`) REFERENCES `address` (`Id`)
);


The foreign key effectively says the same as the generator tag in the mapping XML: The “Id” column in the “person” table references the “Id” column in the “address” table.

Note

I found the order of referencing to be a bit counter intuitive. In the object world, the parent references the child (person -> address). In the database however, the parent uses the id of the child (see next) and I expected the opposite. But when you’ve come to think of it, it’s not that illogical. You do not want your child to be dependent of the parent. That would disable re-use of the child in other mappings because it would always need its parent for generating an id.

To make the mapping bidirectional:

To make the mapping bidirectional you must of course add a property for the parent to the child class:

// The child class
public class UAddress 
{ 
   // More members here, see sample code 
   public BPerson Occupant 
   {
      get { return this.occupant; }
      set { this.occupant = value; }
   }
}                   

// The parent class doesn't change


Then you specify a <one-to-one> tag in the child mapping file also.

<class name="BiDirectional.People.BAddress, 
         NHibernateOneToOne" table="address">
   <id name="Id">
      <generator class="native" />
   </id>
<property name="Street"/>
<one-to-one name="Occupant" 
         class="BiDirectional.People.BPerson, 
         NHibernateOneToOne"/>	
</class>

Namespaces and NHibernate
As you can see from the sample code, I’ve prefixed all classes in the UniDirectional namespace with the letter ‘U’, and those in the BiDirectional namespace with ‘B’. I thought it would have been possible to just use namespaces to differentiate the class. But somehow I didn’t get NHibernate to accept this. Allthough the equally named classes where in different namespaces, NHibernate kept complaining about duplicate class names. So I had to use a prefix to make the names different in the namespaces. That is why in the UniDirectional namespace you can find classes with the ‘U’ prefix (like UFoo, UBar) and in the BiDirectional namespace you can find classes with the ‘B’ prefix (like BFoo, BBar).

Using the <many-to-one> mapping tag

To make a one to one mapping using this tag requires that the key identifying the child record is known as a separate field in the parent table. To achieve this you must do the following:

We have two classes which we want to associate in a parent-child relationship. The parent class is the UCubicle class and the child class is the UProgrammer class.

On the code side:

On the code side, everything is the same as when using the <one-to-one> mapping tag.

On the mapping side:

On the mapping side, again we must somehow associate the id of the child class with the parent class. In this case we use the <many-to-one> tag on the parent classes mapping file. Because we store the id of the child object in a separate field of the table of the parent object we need no special construct for the id generator as with the <one-to-one> tag:

<many-to-one name="Engineer" 
         class="UniDirectional.Office.UProgrammer, 
                   NHibernateOneToOne" 
         column="ProgrammerId"
         cascade="all"/>


What we are saying here is that our type has a property of type UniDirectional.Office.UProgrammer, with the name “Engineer” and that the reference is made by storing the id of the type UniDirectional.Office.UProgrammer in the table column “ProgrammerId”.
The cascade attribute makes sure the correct order is used by NHibernate when manipulating the parent object (like first saving the child and then the parent, in order to be able to use the child’s assigned id for storing in the parents table).

The mapping file for the child class is a standard mapping file.

Note

I’ve tried not including the ‘cascade’ attribute but didn’t have any luck. First their was an error from the database about the field in the parnet table storing the id of the child table not being allowed a null value. After removing the constraint to this field in the table of not allowing null, NHibernate itself started complaining. It stated that the child object should be saved first so it could retrieve it’s id for use when storing the parent table.
A fair requirement, but then why should I use this attribute in the first place? Why not use this order of storing by default?

On the database side:

On the database side setup the parent table to have a field with a simple integer value to store the id of the child data.

CREATE TABLE `cubicle` (
  `Id` int(10) unsigned NOT NULL auto_increment,
  `Name` varchar(45) NOT NULL default '',
  `ProgrammerId` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`Id`)
);

CREATE TABLE `programmer` (
  `Id` int(10) unsigned NOT NULL auto_increment,
  `Name` varchar(45) NOT NULL default '',
  PRIMARY KEY  (`Id`)
);


The field ProgrammerId in the table cubicle receives the id value of the associated record in the programmer table.

To make the mapping bidirectional:

To make the mapping bidirectional you must specify a <one-to-one> tag in the child mapping file.

<one-to-one name="Place" 
   class="BiDirectional.Office.BCubicle, 
      NHibernateOneToOne"/>

Using the <component> mapping tag

To make a one to one mapping using this tag does not require the child class to have an id key.

We have two classes which we want to associate in a parent-child relationship. The parent class is the ParkingPlace class and the child class is the Car class.

On the code side:

// The child class
public class Car 
{ 
   // More members here but no Id property, see sample code 
}                   

// The parent class
public class ParkingPlace 
{ 
   // Id property for parent class needed
   public int Id 
   {
      get { return this.id; }
      set { this.id = value; }
   }
						
   // More members here, see sample code 
   public Car ParkedCar 
   { 
      get { return this.parkerCar; } 
      set { this.parkerCar= value; } 
   } 
}

On the mapping side:

On the mapping side there is no association of id’s because the child class doesn’t have an id. Instead the mapping of the child is declared insode teh mapping of the parent through a <component> tag:

<class name="UniDirectional.ParkingLot.ParkingPlace, 
            NHibernateOneToOne" table="parkinglot">
   <component name="ParkedCar" 
         class="UniDirectional.ParkingLot.Car, 
            NHibernateOneToOne">
      <property name="CarMake"/>
   </component>
</class>


The <component> tag can be seen as a special <property> tag which specifies that the property is of type UniDirectional.ParkingLot.Car and that the properties of that type get mapped to fields of the “parkinglot” table itself. The <property> tags inside the <component> tag specify which properties of the child map to which fields in the table.

Because the mapping of the child is specified directly in the mapping of the parent, there is no mapping file specifically for the child.

On the database side:

On the database side we store all properties for both objects in the same table:

CREATE TABLE `parkinglot` (
  `Id` int(10) unsigned NOT NULL auto_increment,
  `ParkingPlaceId` int(10) unsigned NOT NULL default '0',
  `CarMake` varchar(45) NOT NULL default '',
  PRIMARY KEY  (`Id`)
);

What’s next?

I’m not sure. I would like to elaborate on this one-to-one mapping by examining some CRUD operations with such types, but there’s also many-to-one and one-to-many mappings to be explored. We’ll see…

Updates

24 July 2006: original version
3 September 2006: added section about namespaces not supported in NHibernate

Advertisements

22 thoughts on “NHibernate Part 3: Mapping techniques for aggregation – One To One mapping

  1. Hello,

    I have enjoyed all five of your tutorials, and I am now going back asking the questions that I came up with for each tutorial.

    Before I take you down my NHibernate learning curve, I will ask you my questions, and if these are not clear, please read my attempt to describe my discoveries.

    1.How do I correctly coordinate proxies with lazy loading for behavior.
    2.What is the best resource for NHibernate.

    I decided to move your tutorials to NHibernate 1.2 Beta NH 1.2. Being new to NHibernate, I do not yet know what and where the most active resources are, ???, so any and all direction in this area would be most appreciated.

    In order to get your tutorials to work with NH 1.2, I had to add the following line to the configuration:

    config.SetProperty(Environment.UseProxyValidator, “false”);

    Proxies are the main goal of this post, I am trying to understand the interplay between lazy, proxy, lifeline, and other subtle items in the Nhibernate universe.

    I will attempt to take you on a chronological journey of my dabblings, and then get to my questions:

    ACTION ONE:
    Leaving the mapping as it was in your tutorial I created a function that simply set up a session and then ran the following lines of code.

    UPerson loadedPerson = session.Load(typeof (UPerson), loadPersonID) as UPerson;

    Console.WriteLine(“Person Id:{0} – Name:{1}”, loadedPerson.Id, loadedPerson.Name);
    Console.WriteLine(“Address Id:{0} – Street:{1}”, loadedPerson.WhereAbouts.Id, loadedPerson.WhereAbouts.Street);

    RESULT ONE:
    When I was only able to actually get an instance of UPerson, and not the UAddress of WhereAbouts, I started digging around.

    ACTION TWO:
    I added lazy=”false” to both the Uperson and Uaddress class tag.

    Initially I added lazy=”false” and YES, or so I thought.

    RESULTS TWO:
    At the execution of
    UPerson loadedPerson = session.Load(typeof (UPerson), loadPersonID) as UPerson;

    Log4Net reported that NHibernate put together a SQL statement that in a single call gave back the Person and the Address.. I Expected this behavior.

    I was still not satisfied, I want my Lazy Load : )

    ACTION THREE:
    I added the keyword virtual to each of my classes public properties,

    RESULT THREE:
    At the execution of
    UPerson loadedPerson = session.Load(typeof (UPerson), loadPersonID) as UPerson;

    NO Log4Net Nhibernate sql, yes, I pressed F10, held my breath, and BAM, this is it….: ) YEAAAA! ALMOST.

    Log4Net reported SQL being generated for just the person during this line of code
    Console.WriteLine(“Person Id:{0} – Name:{1}”, loadedPerson.Id, loadedPerson.Name);

    and for the address for this line of code
    Console.WriteLine(“Address Id:{0} – Street:{1}”, loadedPerson.WhereAbouts.Id, loadedPerson.WhereAbouts.Street);

    OK, I have a little confidence, but because my interest in NHibernate is that I heard that you were not required to artificially adorn your classes in order to work with it, and in my mind having to add virtual to each member of interest for the proxy behavior to work is a slight distraction for me.

    Let the digging continue.

    I finally ran across a blog entry http://dotnet.org.za/eduard/archive/2005/01/25/13622.aspx
    in summary I believe he meant that I can either adorn my classes with the virtual keyword for properties and/or methods, or create an interface for the classes that I am interested in using proxies for.

    So I created interfaces for them, and ran the same function described above, and I did not get anything…..

    So, all of that to ask two questions:
    3.How do I correctly coordinate proxies with lazy loading for behavior.
    4.What is the best resource for NHibernate.

  2. Thanks for the positive comments on my series.

    I’m just starting with NHibernate too, so I’m not sure if I can be of any help.

    If you look in the NHibernate Users FAQ you will see an entry like this:

    Why doesn’t my proxy work?
    To be able to create a proxy for a class, the class should have its properties, methods and events declared as virtual. This is not required if the class is proxied through an interface it implements (specified using proxy=”SomeInterface”). There is no code in NHibernate 1.0 to validate your proxy classes, but that will be added in NHibernate 1.1.

    NHibernate uses the library Castle.DynamicProxy that is part of the Castle Project. DynamicProxy generates IL – not modifying your IL – at runtime for a subclass of your class, or the IL to implement an interface.

    I suppose this confirms what you found out the hard way.

    NHibernate uses the Castle project for creating it’s proxies, and this project requires virtual methods and properties to know what to override.

    I remember experimenting with an AOP framework using the same DynamicProxy and having experienced the same: no virtual methods was no aspect weaving.

    I agree with your conclusion that this violates the transparency which you wish.

    Your questions about resources:
    I’ve read Hibernate in Action and started experimenting.

    I haven’t found any definite resources on NHibernate myself. Even the documentation is not very thourough. That’s why I started experimenting myself and wrote these articles. This way others can learn from my experience.

    Keep checking for updates and new articles. If you should find any illuminating articles or resources, please post them in the comments.

  3. Hello Again,

    Ok, I am now fully comprehending both the structural elements of NHibernate as well as Proxy as it relates to Lazy Loading, I have a fairly confident understanding of how and when to use batching, so now I am working towards using the NHibernate 1.2.0’s ability to work with .NET 2.0 Generics….

    I am just stepping in to this.

    When I try to IQuery multiple User Entities into a IList. My intellisense indicates that NHibernate supports this overload, yet I have yet to get this to work.

    NHibernates ability to work with Generics has been what I have been waiting for before investing the time to fully embrace it.

    Any and all help on this would be very valuable.

    Lenny

  4. Hi,

    Greate sample – I found it really clear and useful.

    There still is one thing I’m trying to discover.

    In your UPerson class, you have a piece of redundant (maybe even dangerous) data – the id. The WhereAbouts property is useful and it also contains your primary key (in the Id of the UAddress).

    In for example, TopLink, you could define the WhereAbouts property as the primary key and it would figure out what to do. (Not so intuative with Person-Address, but is ituative in some cases.)

    But in hibernate, if I set WhereAbouts as I get NHibernate.MappingException : could not determine a property type for: …

    Do you know is there a way around this?

    Roger

  5. Thanks for the positive comments.

    I’m not sure what you mean.

    Yoy can not ommit the Id property on the UPerson class. If you do NHibernate will complain about having a, and I quote; “Problem trying to set property type by reflection”.

    In theory you do have two times the same information, so in that respect it is redundant. NHibernate does however need it to function properly.

    As for your second remark: what exactly did you do? (I believe a piece of your sentence got lost in cyberspace 😉 ):
    But in hibernate, if I set WhereAbouts as <EATEN BY CYBERSPACE> I get NHibernate.MappingException : could not determine a property type for: …

  6. Hi Serge,

    The bit eaten was “id” in angle brackets.

    What I mean is this:

    In general if a column C, say of type int, in table A has a foreign key constraint to the PK of table B, then with hibernate you would have class A with a property C of type B (not int). This is nice.

    So in the case where C not just any column, but is the primary key of A, then would be nice to still have in class A that property C is of type B and not int.

    As I mentioned this would not be very intuative for the Person, Address example, but I have come accross a DB that we wrapped with Java and TopLink in the past where there was a table “ApplicationForm” that represented a form with many optional sections. Each section had been modeled in the DB as a table with PK that was FK to ApplicationForm. Each class representing a section had a property of type ApplicationForm that was represented in TopLink as the “id” (PK) field. So no extra redundant integer type property in the section classes.

    I hope that makes it a little more clear.

    Regards,

    Roger

  7. Hi Roger,

    I understand what you mean, but couldn’t find a way how to do this in NHibernate.

    I did find somewhere in the documentation of NHibernate a sentence stating the following:

    Mapped classes must declare the primary key column of the database table. Most classes will also have a Property holding the unique identifier of an instance. The element defines the mapping from that property to the primary key column.

    This setence suggests that it isn’t necessary to have an Id property but only to have a primary key declaration from the table to the class. That should make possible what you suggest, although perhaps not with the same convenient syntax. I could however not find a way to only declare this primary key without mapping it to a property.

    Maybe someone with more experience on mapping with NHibernate could answer this question… If you ever get an answer, please post a comment.

  8. Hi Serge,
    Really enjoyed the great series!

    You mention about having to qualify the name of classes with a U or B even though the classes are in a different namespace. I had a little dig around on the NHibernate forum and found that you can avoid this by setting the auto-import attribute to false on the hibernate-mapping element in the .hbm.xml

    (see http://forum.hibernate.org/viewtopic.php?t=952659&highlight=schemaexport )

    This however does introduce another issue – it forces you to use the fully qualified name of these classes in hql queries (as per your example).

    Christian

  9. NHibernate best practices suggest you leave that Id property in your class, even though it doesn’t make sense from an Oop standpoint; this is really shadow information about your DTO, and useful for testing.

    You may leave the name= desgination out of the id node, and Hibernate will not attempt to find your primary key property

  10. I am using the tag to make a one-to-one mapping.While updating the records NHibernate usually performs a delete and an insert on the parent table. But in this case it is not deleting the old record from the parent table.It is adding a new record to the parent table and updating the foreign key column of the child table.As a result my table becomes bigger whenever there is an update.Please tell me if I am missing anything here.

  11. I am using the many-to-one tag to make a one-to-one mapping.While updating the records NHibernate usually performs a delete and an insert on the parent table. But in this case it is not deleting the old record from the parent table.It is adding a new record to the parent table and updating the foreign key column of the child table.As a result my table becomes bigger whenever there is an update.Please tell me if I am missing anything here.

  12. Rajesh,

    can you specify the differnce betwwn “usually” and “in this case”? From what you are writing I guess it sometimes succeeds and in other cases fails. What are you doing in both cases and more importantly: what are you doing differently?

    Serge

  13. Serge,
    Thank you for your response. I was making a mistake in updating the objects. I was able to resolve the problem.

  14. RealEstate
    ———–
    id (auto increment)
    Title
    Address
    Price
    CategoryId
    ..
    ..
    ..

    Deed
    ——-
    id (auto increment)
    EstateId
    Name
    LastName
    Bla
    Bla
    Bla

    I want to get Deed class as a child when i get RealEstate(parent class)

    This situation and my db table designs are not suitable for the methods you have mentioned above.

    Could you please help me to figure out

  15. @Barbaros

    I suppose you’re not able to update the schema of your database?

    Otherwise the solution is simple:
    1/ either remove the identity definition from your RealEstate table
    2/ or add a DeedId column to your RealEstate table

    Regards

  16. Hi. i have a problem with one-to-one of kind
    generator is foreign
    i’m taking the follow exception:”null identifier”
    can you help me?
    thanks!!!

    1. Hi Diego,

      That is of course very little information to make an analysis.

      Could you please provide some more information on when exactly you got the exception? Do you get it in my code or in code of your own. If in your own code, could you please provide a litttle sample application which reproduces the error?

      Serge

  17. Hi,

    This article is really very useful. As a new comer for Nhibernate, it helped me to resolve the foreignkey issues while saving the data. Thanks a lot for such a great article. I would like to see other posts also in future.

    Regards
    Jaimin Gandhi.

  18. Great article. I find using the tag for a one-to-one relationship very confusing and was stuck with the ‘Cannot insert null’ error for a few days. This article cleared it up for me thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s