Logo

NHibernate

The object-relational mapper for .NET

NH2.1.0: New generators

This post is an recognition that we had lost the fight with Identity's fans. As you probably know I don’t like Identity, but as a NHibernate-developer I can’t ignore ours users requests.

This is the complete list of POID (Persistent Object IDentifier) generators provided by NHibernate2.1.0:

  • native
  • identity (improved)
  • sequence
  • hilo
  • seqhilo
  • assigned
  • guid
  • guid.comb
  • guid.native (new)
  • select (new)
  • sequence-identity (new)
  • trigger-identity (new)
  • uuid.hex
  • uuid.string
  • counter
  • increment
  • foreign

guid.native

Is a new generator that allow to use the RDBMS native function to generate GUID. The behavior is similar to the “sequence” generator: when a new object is saved NH run two query; the first to retrieve the GUID value and the second to insert the entity using the Guid retrieved from RDBMS. The type in your entity is System.Guid and the SQLtype depend from the dialect (RAW(16) in Oracle, UniqueIdentifier in MsSQL for example).

Queries that runs in ORACLE are:

  1. select rawtohex(sys_guid()) from dual
  2. INSERT INTO MyEntityTable (Id, Description) VALUES (:p0, :p1)

The  parameter “:p0” has the value retrieved in the first query.

sequence-identity

The “sequence-identity” is based on “sequence” but work as an “identity”. The POID values is retrieved with the INSERT query. The types, in your entity, maybe are System.Int32 or System.Int64 depending on your RDBMS sequence generator.

The query that run in ORACLE is:

INSERT INTO my_entity (id, name) VALUES (hibernate_sequence.nextval, :p0) returning id into :nhIdOutParam

The “hibernate_sequence” is the default name for a sequence where no alternative name is provided trough the mapping. As you can see, in this case, the “sequence” are working like “identity”, the value of the POID is retrieved immediately and the generator has the same problem of “identity”.

trigger-identity

The “trigger-identity” is a NHibernate specific feature where the POID is generated by the RDBMS at the INSERT query trough a BEFORE INSERT trigger. In this case you can use any supported type, including custom type, with the limitation of “single-column” (so far).

The query in ORACLE is:

INSERT INTO my_entity (Name) VALUES (:p0) returning Id into :nhIdOutParam

As you can see the query is very similar to the query used to work with “identity”; the “Id” field is not present in the FieldsNameList nor in VALUES list and the value of the POID is retrieved immediately. What the trigger are doing to generate the “Id” field value is out-side of NH scope.

select

The “select” generator is a deviation of the “trigger-identity”. This generator work together with natural-id feature. The difference “trigger-identity” is that the POID value is retrieved by a SELECT using the natural-id fields as filter. In practice giving

<class name="MyEntity" table="my_entity">
<
id name="id">
<
generator class="select"/>
</
id>
<
natural-id>
<
property name="name"/>
</
natural-id>
</
class>

and having a trigger to generate the POID, the queries runs in ORACLE are:

  1. INSERT INTO my_entity (name) VALUES (:p0)
  2. SELECT id FROM my_entity WHERE name = :p0

The POID still retrieved immediately.

identity

The “identity” generator is well known by NH<->MsSQL users but, before NH2.1.0, can’t be used for others RDBMS if the RDBMS don’t support native identity-generator. What happen if you have one multi-RDBMS-application and your DBA want use an identity-style generator in each RDBMS ? Which is your work with mappings files for NHibernate ? Well… we have changed the meaning of “identity”. In NH2.1.0 defining <generator class="identity"/> your are saying : “I want work with an identity-style generator; check my dialect to know which is the correct generator for identity”.

By default, when you specify “identity”, NH run the follow:

if (SupportsIdentityColumns)
{
return typeof(IdentityGenerator);
}
else if (SupportsSequences)
{
return typeof(SequenceIdentityGenerator);
}
else
{
return typeof(TriggerIdentityGenerator);
}

If you need a different behavior you can inherit from the default dialect, for your RDBMS, and override the property IdentityStyleIdentifierGeneratorClass.

Conclusion

Now you have a more easy way to break the unit-of-work pattern, and to nullify the batcher, for all NH’s supported dialects: specify “identity” as your identifier generator.


Posted Mon, 09 February 2009 02:12:00 PM by fabiomaulo
Filed under: identity, NH2.1, generators

comments powered by Disqus
© NHibernate Community 2024