Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent NHibernate optimistic lock

I am trying to configure op-locking using fluent nhibernate.

There is a lot of info out there but none seems to fit the scenario I'm in. My class and map are as follows (edited for brevity):

Entity:

public class EmailGroup : CRUDDomainObject<EmailGroup>
{        
    public virtual string Id { get; set; }
    public virtual MailServer Server { get; set;}
    public virtual string FromAddress { get; set;}
    public virtual string ToAddress { get; set;}
    public virtual long Version { get; set; }    
}

Map:

public class EmailGroupMap : ClassMap<EmailGroup>
{
    public const string TABLE_ID = "EMAILGROUP";

    public const string FIELD_ID = "EMAILID";
    public const string FIELD_MAIL_SERVER = "MAILSERVID";
    public const string FIELD_FROM_ADDRESS = "EMLFROM";
    public const string FIELD_TO_ADDRESS = "EMLTO";
    public const string FIELD_VERSION = "VERSION";

    public EmailGroupMap()
    {
        Table(TABLE_ID);

        Id(x => x.Id)
            .Column(FIELD_ID)
            .Not.Nullable()
            .GeneratedBy.Assigned()
            .Length(12);

        References(x => x.Server)
            .Column(FIELD_MAIL_SERVER)
            .NotFound.Ignore();

        Map(x => x.FromAddress)
            .Column(FIELD_FROM_ADDRESS)
            .Not.Nullable()
            .Length(120);

        Map(x => x.ToAddress)
            .Column(FIELD_TO_ADDRESS)
            .Not.Nullable()
            .Length(1000);

        Version(X => X.Version)
            .Column(FIELD_VERSION)
            .Generated.Always()
            .UnsavedValue("0")
            .Access.Property();

        DynamicUpdate();

        OptimisticLock.Version();
    }
}

All looks well to me here, but when I load the entity and modify it, the version number is not incremented. Likewise if I manually increment the version, while a session is open, I get no StaleObjectException.

Does this config look valid to the more experienced eye? If so what else could I be missing?

UPDATE:

After implementing a database managed timestamp the version column is (of course) being incremented. However NHibernate doesn't treat the row as optimistically locked. I captured the update query from the SQL server to check the where clause (truncated for brevity):

exec sp_executesql N'UPDATE [EMAILGROUP] 
SET [EMLDESC] = @EMLDESC, [MAILSERVID] = @MAILSERVID, [EMLFROM] = @EMLFROM, [EMLTO] = @EMLTO, [EMLCC] = @EMLCC, [EMLBCC] = @EMLBCC 
WHERE [EMAILID] = @EMAILID'
like image 498
Arjun Sol Avatar asked Feb 20 '26 17:02

Arjun Sol


2 Answers

Why did you specify Generated.Always()? That tells NHibernate that this isn't a real column but instead calculated by the database. Documentation: http://nhibernate.info/doc/nh/en/index.html#mapping-generated

Remove that and it should work.

like image 123
cremor Avatar answered Feb 24 '26 15:02

cremor


The most typical scneario for Version and SQL Server (not sure if this is your case) is the sql type timestamp (obsolete) or better rowversion. This should be mapped to C# byte[]. So these changes should solve it:

1) Version column on the server must be of type rowversion (or timestamp). Such a column is automatically updated on any changes related to current row. only one such column can exist per table

2) The entity should look like this

public class EmailGroup : CRUDDomainObject<EmailGroup>
{        
   ...
   public virtual byte[] Version { get; set; }  

3) the fluent mapping code should remain as it is. It should be a job of a fluent mapper to do the tricks behind. what we need to achieve is something like this:

<version name="Version" generated="always" unsaved-value="null"  type="BinaryBlob">
    <column name="Version" not-null="false" sql-type="timestamp"/>
</version>

Please, see more here: http://ayende.com/blog/3946/nhibernate-mapping-concurrency

like image 36
Radim Köhler Avatar answered Feb 24 '26 17:02

Radim Köhler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!