NHibernate and the composite-id.

Thursday, March 19, 2009 11:23 AM | Leave a reply »

I’m working with the new version (2.0 GA) of NHibernate. The problem I have encountered today is about the composite-id.

Let’s say we have an entity that doesn’t have a personal id field. We don’t want to use the GUID or any other auto id generator class. We must implement the primary key logic in the corresponding table in the database. Now, imagine to have this table:

Key Column Name SQL Type Not null
yes Field01 varchar true
yes Field02 varchar true
yes Field03 varchar true
yes Field04 varchar true


At this point we will have a mapping XML in NHibernate in this way:

   1: <class name="classname" table="[tablename]" schema="schemaname">
   2:   <composite-id>
   3:     ... ...
   4:     <key-property name="Field02">
   5:       <column name="[Field02]" sql-type="varchar" length="5" not-null="true"/>
   6:     </key-property>
   7:     <key-property name="Field03">
   8:       <column name="[Field03]" sql-type="varchar" length="5" not-null="true"/>
   9:     </key-property>
  10:     ... ...
  11:   </composite-id>

If we compile the DAL of our project, we will receive a fancy error:

“composite-id class must override Equals()”

“composite-id class must override GetHashCode()”

The explanation is very simple. We are saying that this class has 3 fields to implement a comparison so the NHB must know how you can compare these fields … and off course the CLR doesn’t know how to do it.

This is the solution in our entity:

   1: public override bool Equals(object obj) {
   2:     if (obj == null)
   3:         return false;
   4:     MyEntity t = obj as MyEntity;
   5:     if (t == null)
   6:         return false;
   7:     if (this.f1 == t.f1 && this.f2 == t.f2 && this.f3 == t.f3)
   8:         return true;
   9:     else
  10:         return false;
  11: }
   1: public override int GetHashCode() {
   2:     int hash = 13;
   3:     hash = hash +
   4:       (null == this.f1 ? 0 : this.f1.GetHashCode());
   5:     hash = hash +
   6:       (null == this.f2 ? 0 : this.f2.GetHashCode());
   7:     hash = hash +
   8:       (null == this.f3 ? 0 : this.f3.GetHashCode());
   9:     return hash;
  10: }

There we go!! Now you have implemented a full version of the method “Hey is this the entity I’m going to save or is this entity brand new?!?!”

Personal Consideration.

In my opinion NHB should be able to override this method by itself via reflection and not to ask you to rebuild thousand of entities if you want to use the standard pattern active Record.


Comments

  1. Re : # re: NHibernate and the composite-id.

    Thanks for your post. Here's similar code but in C#.


    ///
    /// Get whether composite keys specified are the same
    ///

    public override bool Equals(object obj)
    {
    bool equals = false;

    if (null != obj)
    {
    MEmailFormat temp = obj as MEmailFormat;
    if (null != temp)
    {
    equals = (this.Property1 == temp.Property1) &&
    (this.Property2 == temp.Property2);
    }
    }

    return equals;
    }

    ///
    /// Get hash code
    ///

    public override int GetHashCode()
    {
    int hash = 1122;

    hash += (null == Property1 ? 0 : Property1.GetHashCode());
    hash += (null == Property2 ? 0 : Property2.GetHashCode());

    return hash;
    }
  2. Gravatar aex says:

    Re : # re: NHibernate and the composite-id.

    Hey, thank you so much, this is an excellent article. Please keep up the good work! :)
  3. Gravatar raffaeu says:

    Re : # re: NHibernate and the composite-id.

    The source code is now available on Codeplex. Check the articles, in each one I have added a DIV with the source code address.
    Enjoy!
  4. Re : # re: NHibernate and the composite-id.

    I was searching on the web for the same thing, found..but couldn’t figure out how to run..I did have problems with this so plz solve my problem..
  5. Re : # re: NHibernate and the composite-id.

    I think I understand this solution, except for the seemingly arbitrary initial hash values. Why does the java code set it to 13 and the C# code set it to 1122. I'm new to C# so please let me in on what you guys were thinking!

    Thanks!
  6. Gravatar raffaeu says:

    Re : # re: NHibernate and the composite-id.

    As you said the number is absolutely arbitrary.
    If it is a prime number is logical better. ;-)
Comments have been closed on this topic.