复合Key和继承

发布于 2024-12-09 14:54:03 字数 2763 浏览 0 评论 0原文

我有以下类和映射

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>();
}

i have the following classes and mappings

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");
    }
}

inserting, updating and session.Get() work fine but querying like

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

throws

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)
...

it seems NH tries to instantiate the abstract baseclass as a compositekey and fails. Can i somehow work around that?

UPDATE: my testcode

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>();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拥抱没勇气 2024-12-16 14:54:03

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

编辑:NHibernate 映射中有一个 abstract="true" 属性,它可能会解决您的问题。但似乎这在 Fluent NHibernate 中并未针对 ClassMap 公开,仅针对 SubclassMap (这对您没有帮助)。

但也许您也可以通过使用复合 ID 的组件来解决问题(这样 NHibernate 就不需要为其 EntityKey 创建 BaseClass 对象。请参阅 此处 了解相关信息。

How does your database look like? According to your mapping, you are using a table-per-subclass mapping. In this case NHibernate will try to create an instance of BaseClass if no row is found in the table of InheritingClass.

edit: There is a abstract="true" attribute for a <class> in NHibernate mapping which might fix your problem. But it seems like this isn't exposed in Fluent NHibernate for a ClassMap, only for SubclassMap (which won't help you).

But maybe you could also fix the problem by using a component for the composite ID (so that NHibernate doesn't need to create a BaseClass object for its EntityKey. See here for infos about that.

渔村楼浪 2024-12-16 14:54:03

谢谢克雷莫,这就是我最终得到的结果

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,
    }
};

thx to cremor this is what i end up with

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,
    }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文