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 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">class</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="classname"</span> <span style="color: #ff0000">table</span><span style="color: #0000ff">="[tablename]"</span> <span style="color: #ff0000">schema</span><span style="color: #0000ff">="schemaname"</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum2" style="color: #606060"> 2:</span> <span style="color: #0000ff"><</span><span style="color: #800000">composite-id</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum3" style="color: #606060"> 3:</span> ... ... |
|
1 |
<span id="lnum4" style="color: #606060"> 4:</span> <span style="color: #0000ff"><</span><span style="color: #800000">key-property</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="Field02"</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum5" style="color: #606060"> 5:</span> <span style="color: #0000ff"><</span><span style="color: #800000">column</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="[Field02]"</span> <span style="color: #ff0000">sql-type</span><span style="color: #0000ff">="varchar"</span> <span style="color: #ff0000">length</span><span style="color: #0000ff">="5"</span> <span style="color: #ff0000">not-null</span><span style="color: #0000ff">="true"</span><span style="color: #0000ff">/></span> |
|
1 |
<span id="lnum6" style="color: #606060"> 6:</span> <span style="color: #0000ff"></</span><span style="color: #800000">key-property</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum7" style="color: #606060"> 7:</span> <span style="color: #0000ff"><</span><span style="color: #800000">key-property</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="Field03"</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum8" style="color: #606060"> 8:</span> <span style="color: #0000ff"><</span><span style="color: #800000">column</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="[Field03]"</span> <span style="color: #ff0000">sql-type</span><span style="color: #0000ff">="varchar"</span> <span style="color: #ff0000">length</span><span style="color: #0000ff">="5"</span> <span style="color: #ff0000">not-null</span><span style="color: #0000ff">="true"</span><span style="color: #0000ff">/></span> |
|
1 |
<span id="lnum9" style="color: #606060"> 9:</span> <span style="color: #0000ff"></</span><span style="color: #800000">key-property</span><span style="color: #0000ff">></span> |
|
1 |
<span id="lnum10" style="color: #606060"> 10:</span> ... ... |
|
1 |
<span id="lnum11" style="color: #606060"> 11:</span> <span style="color: #0000ff"></</span><span style="color: #800000">composite-id</span><span style="color: #0000ff">></span> |
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 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> Equals(<span style="color: #0000ff">object</span> obj) { |
|
1 |
<span id="lnum2" style="color: #606060"> 2:</span> <span style="color: #0000ff">if</span> (obj == <span style="color: #0000ff">null</span>) |
|
1 |
<span id="lnum3" style="color: #606060"> 3:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; |
|
1 |
<span id="lnum4" style="color: #606060"> 4:</span> MyEntity t = obj <span style="color: #0000ff">as</span> MyEntity; |
|
1 |
<span id="lnum5" style="color: #606060"> 5:</span> <span style="color: #0000ff">if</span> (t == <span style="color: #0000ff">null</span>) |
|
1 |
<span id="lnum6" style="color: #606060"> 6:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; |
|
1 |
<span id="lnum7" style="color: #606060"> 7:</span> <span style="color: #0000ff">if</span> (<span style="color: #0000ff">this</span>.f1 == t.f1 && <span style="color: #0000ff">this</span>.f2 == t.f2 && <span style="color: #0000ff">this</span>.f3 == t.f3) |
|
1 |
<span id="lnum8" style="color: #606060"> 8:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>; |
|
1 |
<span id="lnum9" style="color: #606060"> 9:</span> <span style="color: #0000ff">else</span> |
|
1 |
<span id="lnum10" style="color: #606060"> 10:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; |
|
1 |
<span id="lnum11" style="color: #606060"> 11:</span> } |
|
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">int</span> GetHashCode() { |
|
1 |
<span id="lnum2" style="color: #606060"> 2:</span> <span style="color: #0000ff">int</span> hash = 13; |
|
1 |
<span id="lnum3" style="color: #606060"> 3:</span> hash = hash + |
|
1 |
<span id="lnum4" style="color: #606060"> 4:</span> (<span style="color: #0000ff">null</span> == <span style="color: #0000ff">this</span>.f1 ? 0 : <span style="color: #0000ff">this</span>.f1.GetHashCode()); |
|
1 |
<span id="lnum5" style="color: #606060"> 5:</span> hash = hash + |
|
1 |
<span id="lnum6" style="color: #606060"> 6:</span> (<span style="color: #0000ff">null</span> == <span style="color: #0000ff">this</span>.f2 ? 0 : <span style="color: #0000ff">this</span>.f2.GetHashCode()); |
|
1 |
<span id="lnum7" style="color: #606060"> 7:</span> hash = hash + |
|
1 |
<span id="lnum8" style="color: #606060"> 8:</span> (<span style="color: #0000ff">null</span> == <span style="color: #0000ff">this</span>.f3 ? 0 : <span style="color: #0000ff">this</span>.f3.GetHashCode()); |
|
1 |
<span id="lnum9" style="color: #606060"> 9:</span> <span style="color: #0000ff">return</span> hash; |
|
1 |
<span id="lnum10" style="color: #606060"> 10:</span> } |
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.

Recent Comments