As always, business requirement went over existing code base to ask for a minor change that wasn’t compatible with our existing infrastructure: all surrogate keys are unique identifiers (Guid) and all infrastructure was built around that. The business people asked to add to an existing domain entity a natural key - integer identity number (auto increment field), to serve as a reference number.
We had two choices:
- to generate the identity from business code
- to let database manage it for us.
The second approach it preferable for us because it’s the database’s job to generate the keys.
Out of the box NHibernate doesn’t support such a thing. Answers to my question in NHibernate Users discussion group led to the next solution.
Given the class:
public class Entity
{
public int Id { get; set; }
public int Id2 { get; set; }
}
First “Id” is the primary key, the second is the key that we want to map to identity column. To have that done we should do two things:
- Map “Id2” property as “generated”
- Use “database-object” to drop the column generated by NHibernate & create new one, with IDENTITY set on.
The complete mapping:
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
namespace="NHibernate.Playground"
assembly="NHibernate.Playground"
default-lazy="false" xmlns="urn:nhibernate-mapping-2.2">
<class name="Entity">
<id name="Id">
<generator class="increment" />
</id>
<property name="Id2" type="int" generated="always" insert="false" />
</class>
<database-object>
<create>
ALTER TABLE Entity DROP COLUMN Id2
ALTER TABLE Entity ADD Id2 INT IDENTITY
</create>
<drop>
ALTER TABLE Entity DROP COLUMN Id2
</drop>
</database-object>
</hibernate-mapping>
I like the flexibility offered by NHibernate. Even if you don’t have required feature, you can always use naked ADO.NET or raw SQL.