I've a rather large domain-model that persists using fluent NHibernate to MS SQL Server 2008.
Recently we've been running into concurrency problems, so I implemented Versioning NHibernate's excellent Version with an eye to using MSSQL's timestamp
datatype. All my entities subclass the cunningly named DomainEntity
abstract class, which has the following IAutoMappingOverride
:
public class DomainEntityOverride : IAutoMappingOverride<DomainEntity> {
public void Override(AutoMapping<DomainEntity> mapping) {
mapping.OptimisticLock.Version();
mapping.Version(entity => entity.Version);
}
}
Furthermore I set up the versioning using an IVersionConvention
:
public class VersionConvention : IVersionConvention {
public void Apply(IVersionInstance instance) {
instance.Column("Version");
instance.Generated.Always();
instance.UnsavedValue("null");
instance.Not.Nullable();
instance.CustomSqlType("timestamp");
}
}
My understanding is that this should cause the Version to always be generated, and checked for concurrency issues. In my dev and production environments (both using MSSQL2008) it seems to work, but my in-memory tests using SQLite no longer work.
A basic test that now fails is the following:
[Test(Description = "Can save an aircraft and it is persisted")]
public void PersistAircraft_NewAircraft_AircraftIsPersisted() {
var id = saveEntity(_aircraft); //exception thrown here
var persisted = getEntity<Aircraft>(id);
Assert.That(persisted.Registration, Is.EqualTo(_aircraftRegistration));
Assert.That(persisted.Remarks, Is.EqualTo(_aircraftRemark));
}
I get the follwing exception:
Test 'NOIS.Persistence.Tests.InMemory.AircraftPersistenceTest.PersistAircraft_NewAircraft_AircraftIsPersisted' failed: NHibernate.Exceptions.GenericADOException : could not insert: [NOIS.Model.Entities.AircraftType#9c2809ea-c0c5-4778-838b-9e2500a6d2ef][SQL: INSERT INTO "AircraftType" (ProducedBy, Active, Remarks, Name, Code, Category_id, Id) VALUES (?, ?, ?, ?, ?, ?, ?)]
----> System.Data.SQLite.SQLiteException : Abort due to constraint violation
AircraftType.Version may not be NULL
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Object obj, ISessionImplementor session) at NHibernate.Action.EntityInsertAction.Execute() at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) at NHibernate.Engine.ActionQueue.ExecuteActions() at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) at NHibernate.Impl.SessionImpl.Flush() at NHibernate.Transaction.AdoTransaction.Commit() FluentlyConfiguredInMemoryDatabaseTest.cs(49,0): at NOIS.Persistence.Tests.FluentlyConfiguredInMemoryDatabaseTest.saveEntity(DomainEntity entity) InMemory\AircraftPersistenceTest.cs(33,0): at NOIS.Persistence.Tests.InMemory.AircraftPersistenceTest.PersistAircraft_NewAircraft_AircraftIsPersisted() --SQLiteException at System.Data.SQLite.SQLite3.Reset(SQLiteStatement stmt) at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) at System.Data.SQLite.SQLiteDataReader.NextResult() at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave) at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior) at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session)