Friday, January 27, 2012

Mapping-by-Code - concurrency

It's time for less exhausting topic - concurrency mapping. There are two different aspects of concurency-related mappings.

The first one is entity-level mapping, where we choose the concurrency model (for optimistic concurrency). In XML, in <class> mapping, there are two attributes regarding the optimistic concurrency - optimistic-lock and dynamic-update. The former is not supported in mapping-by-code. The latter can be set using simple method in ClassMapping:

DynamicUpdate(true);

Another concurrency model is to use explicit versioning with separate column that keeps either timestamp or version number incremented on each update. In XML, this column is mapped using <version> element. There's corresponding method in mapping-by-code:

Version(x => x.Version, m =>
{
m.Column("columnName");
// or
m.Column(c =>
{
c.Name("columnName");
// etc...
});

m.Generated(VersionGeneration.Always); // or VersionGeneration.Never
m.UnsavedValue(0);
m.Insert(true);

m.Type(new TimestampType());
// or
m.Type<CustomType>();

m.Access(Accessor.Field);
});

The mapping is not a surprise. The first parameter is an expression pointing to mapped property, the second is for the configuration. We can specify column properties using standard Column method. We can define whether the value is generated at database side using Generated method. We can choose what value should be assigned to newly created objects using UnsavedValue method. We can also define whether the value should be considered when building insert query using Insert method. We can choose how NHibernate is accessing the value, using Access method. Finally, using the Type method, we can decide on the type used for versioning - most common are numeric and timestamp types.

Fluent NHibernate equivalents

Entity-level mappings for concurrency options in FNH are available through the two methods:

DynamicUpdate();
OptimisticLock.Dirty(); // or .All(), .None(), .Version()

And here is the mapping for version property:

Version(x => x.Name)
.Column("columnName")
.Generated.Always() // or .Never()
.UnsavedValue("0") // string?
.Access.Field()
.CustomType("timestamp")
// or
.CustomType<CustomType>();

Insert seems to be not supported. UnsavedValue is string-typed, what looks a bit strange i.e. if we want to set it to numeric value.


Two next posts in Ayende's series are about NHibernate properties mapped at global level, above entity level - <database-object>, named queries, <query> and <sql-query>. I'll skip these as they do not fit into mapping-by-code ClassMappings series. I'll maybe come back to it separately.

No comments:

Post a Comment