Nhibernate:拉回 "Table-per-class hierarchy" 中的大多数派生类型

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

我正在解决有关 NHibernate 配置中“Table-per-class 层次结构”设置中几个 <subclass> 元素的问题。当我点击数据库时,我试图获取父 class 的“最派生类型”。 IE。当我获取 EnergySource 对象时,我希望基础类型为 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>

classes 只是:

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 是“延迟加载的”。当我尝试从另一个对象 属性(例如 item.EnergySource)访问 EnergySource 时,我得到了 NHibernate 的“代理”,它可以促进延迟加载,如:

In short... [what we're working with] is a lazy loaded object, NHibernate, at this point in time, has no idea what it is. But since it must return something, it returns a proxy of [our object], which will load the actual instance when needed. [But] that leads to some problems when you want to down cast the value.

有关“问题”的详细信息,请参阅 link。但本质上,一旦我们有了一个代理对象,我们就不能将它转换为它所代理类型的子 class 不幸的是......这里有一些解决方法,取自 links下面:

  • 首先不要让代理存在,方法是使用 lazy="false"
  • 禁用延迟加载
  • 在使用父对象的 class 上,添加属性 lazy="no-proxy" (在我的例子中,这不起作用,但可能是由于旧版本的 NHibernate 或我对文档的理解有误;这当然是它的设计目的):
<many-to-one name="EnergySource" lazy="no-proxy"/>
  • 使用 NHibernate 特定方法“取消代理”对象,创建具有正确类型的新实例,允许转换操作:
  return Session.GetSessionImplementation()
         .PersistenceContext.Unproxy(EnergySource) as Grid;
  • Diegose 提出了一个有趣的解决方法,即在公开 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 

This is a backdoor to the underlying object that NHibernate is managing. It should only be used to access properties of the derived classes. Use polymorphism for behavior. You should never pass the retrieved object to NHibernate methods like Update or Delete.

来源: