繁体   English   中英

Nhibernate:在“表每类层次结构”中撤回大多数派生类型

[英]Nhibernate: Pull back most derived type in "Table-per-class hierarchy"

我正在解决有关 NHibernate 配置中“每类层次结构表”设置中的几个<subclass>元素的问题。 当我点击数据库时,我正在尝试获取父 class 的“最衍生类型”。 即,当我获取EnergySource object 时,我希望基础类型为GridPrimary ,具体取决于<discriminator...>

如果我将属性lazy="false"添加到EnergySource class 配置中,一切实际上都按预期工作。 例如,我可以成功地将EnergySource as Grid进行投射,我可以在EnergySource上使用反射,如果它与鉴别器匹配,我可以运行GetType()并中继:

UnderlyingSystemType: { Name = "Grid" ...

但是通过延迟加载,我得到了一个失败的演员表(只有null )&:

UnderlyingSystemType: { Name = "EnergySourceProxy" ...

这里发生了什么? 根本问题是由延迟加载引起的吗?

我的配置是这样设置的(这是一个旧应用程序):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Domain.EnergySource, Domain" table="library_EnergySource" lazy="true">
  
    <cache usage="read-write" />
    <id name="Id" column="EnergySourceID" unsaved-value="0">
      <generator class="identity" />
    </id>
    
    <discriminator formula="case when EnergySourceTypeID in (1,2,3) then 1 else 4 end" />

    <property name="Name" />
    <many-to-one name="Type" column="EnergySourceTypeID" not-null="true" insert="false" update="false" />
    
    <subclass name="Domain.Grid, Domain"
              extends="Domain.EnergySource, Domain"
              discriminator-value="1">
    </subclass>

    <subclass name="Domain.PrimaryEnergy, Domain"
              extends="Domain.EnergySource, Domain"
              discriminator-value="4">
    </subclass>
  </class>
</hibernate-mapping>

课程只是:

namespace Domain
{
    public class Grid : EnergySource { }
    public class Primary : EnergySource { }
    
    public class EnergySource 
    {
        public virtual string Name { get; set; }
        public virtual EnergySourceType Type { get; set; }
    }
    
    public class EnergySourceType
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
}

本质上,是的,问题在于 class 是“延迟加载的”。 当我尝试从另一个 object 访问EnergySource时,它是一个属性(例如item.EnergySource ),我得到了 NHibernate 的“代理”,它可以促进延迟加载,如下所示:

简而言之...... [我们正在使用的] 是一个延迟加载的 object、NHibernate,目前还不知道它是什么。 但是因为它必须返回一些东西,所以它返回一个 [我们的对象] 的代理,它会在需要时加载实际的实例。 [但是] 当你想降低价值时,这会导致一些问题。

有关更多详细信息,请参阅“问题”链接。 但从本质上讲,一旦我们有一个代理 object,我们就不能将它转换为它所代理的类型的子类,不幸的是......这里有一些解决方法,取自以下链接:

  • 不要让代理存在,首先使用lazy="false"禁用延迟加载
  • 在使用父 object 的 class 上,添加属性lazy="no-proxy" (在我的情况下,这不起作用,但这可能是由于旧版本的 Z111BBE34492093E9894EF9E8B3E01ADZ 或我对文档的理解有误; 这当然是它的设计目的):
<many-to-one name="EnergySource" lazy="no-proxy"/>
  • 使用 NHibernate 特定方法“取消代理” object,创建具有正确类型的新实例,允许强制转换操作:
  return Session.GetSessionImplementation()
         .PersistenceContext.Unproxy(EnergySource) as Grid;
  • Diegose 提出了一个有趣的解决方法,即在父 object 上添加一个属性,该属性公开this ,其工作原理是“泄漏对实际对象的引用”。 这类似于上述选项,但不需要任何特定于 NH 的工作:
public virtual object Actual { get { return this; } }
...
return item.EnergySource.Actual as Grid //Works

他们还提供了通用方法的代码,以进一步简化此过程。 还有一些注意事项,可能也适用于Unproxy方法。

public virtual T As<T>() where T : Entity
{
    return this as T;
}
...

Animal animalProxy = catLover.Pet;
Cat cat = animalProxy.As<Cat>();

// Cat will be the actual object of type Cat
// Or null if animalProxy isn't one 

这是 NHibernate 管理的底层 object 的后门。 它应该只用于访问派生类的属性。 对行为使用多态性。 您永远不应将检索到的 object 传递给 NHibernate 方法,例如更新或删除。

资料来源:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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