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:
- identity (improved)
- guid.native (new)
- select (new)
- sequence-identity (new)
- trigger-identity (new)
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:
- select rawtohex(sys_guid()) from dual
- INSERT INTO MyEntityTable (Id, Description) VALUES (:p0, :p1)
The parameter “:p0” has the value retrieved in the first query.
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”.
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.
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">
and having a trigger to generate the POID, the queries runs in ORACLE are:
- INSERT INTO my_entity (name) VALUES (:p0)
- SELECT id FROM my_entity WHERE name = :p0
The POID still retrieved immediately.
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:
else if (SupportsSequences)
If you need a different behavior you can inherit from the default dialect, for your RDBMS, and override the property IdentityStyleIdentifierGeneratorClass.
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.
feb 09 2009, 09:12 p.m.