Providing insertion after calling a custom NHibernate IIdentifierGenerator

Customization

Some of the "old old old" tables in our database use the exotic primary key generation scheme [1], and I'm trying to overlay this part of the database with NHibernate. This generation scheme is mostly hidden in a stored procedure called, for example, "ShootMeInTheFace.GetNextSeededId".

I wrote IIdentifierGeneratorthat calls this saved proc:

public class LegacyIdentityGenerator : IIdentifierGenerator, IConfigurable
{
    // ... snip ...
    public object Generate(ISessionImplementor session, object obj)
    {
        var connection = session.Connection;

        using (var command = connection.CreateCommand())
        {
            SqlParameter param;

            session.ConnectionManager.Transaction.Enlist(command);

            command.CommandText = "ShootMeInTheFace.GetNextSeededId";
            command.CommandType = CommandType.StoredProcedure;

            param = command.CreateParameter() as SqlParameter;
            param.Direction = ParameterDirection.Input;
            param.ParameterName = "@sTableName";
            param.SqlDbType = SqlDbType.VarChar;
            param.Value = this.table;
            command.Parameters.Add(param);

            // ... snip ...

            command.ExecuteNonQuery();

            // ... snip ...

            return ((IDataParameter)command
                .Parameters["@sTrimmedNewId"]).Value as string);
     }
}

Problem

I can match this in XML mapping files and it works fine, BUT ....

It does not work when NHibernate tries to insert inserts, for example, in a cascade, or when a session fails Flush()after every call Save()on a transition object that depends on this generator.

, NHibernate, , -

for (each thing that I need to save)
{
    [generate its id]
    [add it to the batch]
}

[execute the sql in one big batch]

, , , NHibernate , , , .

NHibernate, IncrementGenerator, , , , . , , , , , , .

  • NHibernate INSERT ? , , .
  • - / , ? , "" - ....

.

: 2

IPreInsertEventListener . , .

The first problem was that setting the idobject to AssignedGenerator, and then not actually assigning anything in the code (since I expected my new implementation IPreInsertEventListenerto do the job) led to the exception being thrown AssignedGenerator, as its method Generate()is essentially Does nothing but check to make sure it is idnot null, otherwise throwing an exception. It works quite easily, creating your own IIdentifierGenerator, which is similar to AssignedGeneratorwithout exception.

, null IIdentifierGenerator (, AssignedGenerator, , NHibernate , , . , IIdentifierGenerator, , "NOT-REALLY-THE-REAL-ID", , IPreInsertEventListener .

, IPreInsertEventListener , , , NHibernate. , . id, IPreInsertEventListeners

  • @event.State, id.
  • id set.
  • , id , "NOT-REALY-REAL-ID" , IPreInsertEventListener .

, , , NHibernate, ", ".

, IIdentifierGenreator : , ID # , Increment:

private string lastGenerated;

public object Generate(ISessionImplementor session, object obj)
{
    string identity;

    if (this.lastGenerated == null)
    {
         identity = GetTheValueFromTheDatabase();
    }
    else
    {
         identity = GenerateTheNextValueInCode();
    }

    this.lastGenerated = identity;

    return identity;
}

, , , Increment, TimeBombGenerator. , , ( , ), lastGenerated , .

@# $@# $@.

, WeakReference ISessions lastGenerated. , lastGenerated ISession, IIdentifierGenerator, WeakReferences Generate() , . ISession , ( , ), ( , phantom ISession, ).

, , 10- . FWIW.


[1] ID, (len-2) , PK, max, , . ( , "1000001", max 10000, +1 10001, 02, PK "1000102". , .

+5
2

, IIdentifierGenerator. IPreInsertEventListener OnPreInsert.

+1

lastGenerated; ?

-2

All Articles