NHibernate and the composite-id.

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.