简体   繁体   中英

NHibernate issue with Session.Lock and abstract base class with Version property

I'm having problems using NHibernate (and Fluent NHibernate) and trying to use the session.Lock functionality when the Version property is on an abstract base class.

I have been able to simplify an example down to the following domain model:

public abstract class AbstractBaseClass : Entity
{
    public virtual int Version { get; protected set; }
    public virtual string Name { get; set; }
}

public class ChildOne : AbstractBaseClass
{
    public virtual string Address { get; set; }
}

My fluent configuration is:

 fluentConfiguration.Mappings(map => map.AutoMappings.Add(
                AutoMap.AssemblyOf<AbstractBaseClass>()
                    .Where(x => x.IsSubclassOf(typeof(Entity)))
                    .IncludeBase<AbstractBaseClass>()
                    .Conventions.Add(DefaultCascade.All())));

When I try to use the Lock method on the session an Exception is thrown by the database provider:

NHibernate.Exceptions.GenericADOException : could not retrieve version: [NHLockTest.ChildOne#1][SQL: SELECT Version FROM "AbstractBaseClass" WHERE Id = ?] ----> System.Data.SQLite.SQLiteException : SQLite error no such column: AbstractBaseClass_id

Here's the unit test I have used to recreate the issue in a simple example:

[Test]
public void Should_Lock_Entity()
{
    using (var session = _sessionFactory.OpenSession())
    {
        var entity = new ChildOne {Address = "Some Address", Name = "Some Name"};
        session.Save(entity);
        session.Flush();
    }

    using (var session = _sessionFactory.OpenSession())
    {
        var entity = session.Query<ChildOne>().Single();
        //this is where the exception is raised
        session.Lock(entity, LockMode.Force); 
    }
}

When I configure NHibernate to show SQL I see the following statement is being generated when the session.Lock call is made:

UPDATE "AbstractBaseClass" 
SET Version = @p0 
WHERE AbstractBaseClass_id = @p1 AND Version = @p2;
@p0 = 2 [Type: Int32 (0)], @p1 = 1 [Type: Int64 (0)], @p2 = 1 [Type: Int32 (0)]

It appears to be trying to update the table for the base class but instead is uing the forign key column name from the child table and not the Id column on the base class table. This clearly doesn't tie up with what the exception message above is saying.

Am I doing something very wrong here or have I found a bug in NHibernate?

In non fluent NHibernate you have to set: polymorphism="explicit" in you XML mapping.

It seems not to work in older versions of fluent nhibernate:

fluent nhibernate convention : setting polymorphism mode

You can try something like (I have not tested it):

fluentConfiguration.Mappings(map => map.AutoMappings.Add(
            AutoMap.AssemblyOf<AbstractBaseClass>()
                .Where(x => x.IsSubclassOf(typeof(Entity)))
                .IncludeBase<AbstractBaseClass>()
                .Polymorphism.Explicit()
                .Conventions.Add(DefaultCascade.All())));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM