复合键和继承

时间:2011-10-14 15:20:26

标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我有以下类和映射

abstract class BaseClass
{
    public virtual int Keypart1 { get; set; }
    public virtual int Keypart2 { get; set; }

    // overridden Equals() and GetHashCode()
}

class InheritingClass : BaseClass
{
}

class BaseClassMap : ClassMap<BaseClass>
{
    public BaseClassMap()
    {
        CompositeId()
            .KeyProperty(x => x.Keypart1)
            .KeyProperty(x => x.Keypart2);
    }
}

class InheritingClassMap : SubclassMap<InheritingClass>
{
    public InheritingClassMap()
    {
        KeyColumn("Keypart1");
        KeyColumn("Keypart2");
    }
}

插入,更新和session.Get()工作正常,但查询

var result = session.CreateCriteria<InheritingClass>().List<InheritingClass>();

引发

NHibernate.InstantiationException: Cannot instantiate abstract class or interface: ConsoleApplication1.BaseClass
   bei NHibernate.Tuple.PocoInstantiator.Instantiate()
   bei NHibernate.Tuple.Component.AbstractComponentTuplizer.Instantiate()
   bei NHibernate.Type.ComponentType.Instantiate(EntityMode entityMode)
   bei NHibernate.Type.ComponentType.Instantiate(Object parent, ISessionImplementor session)
   bei NHibernate.Type.EmbeddedComponentType.Instantiate(Object parent, ISessionImplementor session)
   bei NHibernate.Type.ComponentType.ResolveIdentifier(Object value, ISessionImplementor session, Object owner)
   bei NHibernate.Type.ComponentType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
   bei NHibernate.Loader.Loader.GetKeyFromResultSet(Int32 i, IEntityPersister persister, Object id, IDataReader rs, ISessionImplementor session)
   bei NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies)
...

似乎NH尝试将抽象基类实例化为复合键并失败。我可以以某种方式解决这个问题吗?

更新:我的测试代码

var config = Fluently.Configure()
    .Database(SQLiteConfiguration.Standard.InMemory().ShowSql().FormatSql())
    .Mappings(m => m.FluentMappings
        .Add<BaseClassMap>()
        .Add<InheritingClassMap>()
    )
    .BuildConfiguration();

var sf = config.BuildSessionFactory();

using (var session = sf.OpenSession())
{
    new SchemaExport(config).Execute(false, true, false, session.Connection, null);

    var obj = new InheritingClass
    {
        Keypart1 = 1,
        Keypart2 = 2,
    };

    session.Save(obj);
    session.Flush();
    session.Clear();

    // throws here
    var result = session.CreateCriteria<InheritingClass>().List<InheritingClass>();
}

2 个答案:

答案 0 :(得分:2)

您的数据库是什么样的?根据您的映射,您使用的是每子类表映射。在这种情况下,如果在BaseClass的表中找不到行,NHibernate将尝试创建InheritingClass的实例。

编辑:NHibernate映射中的abstract="true"有一个<class>属性可能会解决您的问题。但似乎Fluent NHibernate中没有公开ClassMap,仅适用于SubclassMap(这对你没用)。

但也许您也可以通过使用组件来解决问题(因此NHibernate不需要为其EntityKey创建BaseClass对象。请参阅here了解有关该问题的信息

答案 1 :(得分:0)

thx to cremor这就是我最终的结果

abstract class BaseClass
{
    public virtual BaseClassId Key { get; set; }
}

class BaseClassId
{
    public virtual int Keypart1 { get; set; }
    public virtual int Keypart2 { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as BaseClassId;
        return (other != null) && (Keypart1 == other.Keypart1) && (Keypart2 == other.Keypart2);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return Keypart1 + Keypart2;
        }
    }
}

// mapping
CompositeId(b => b.Key)
    .KeyProperty(x => x.Keypart1)
    .KeyProperty(x => x.Keypart2);


var obj = new InheritingClass
{
    Key = new BaseClassId
    {
        Keypart1 = 1,
        Keypart2 = 2,
    }
};