c# - 在 NHibernate 中获取正确类型的代理

标签 c# .net nhibernate proxy

我在 nhibernate 中遇到未初始化代理的问题

领域模型

假设我有两个平行的类层次结构:Animal、Dog、Cat 和 AnimalOwner、DogOwner、CatOwner,其中 Dog 和 Cat 都继承自 Animal,而 DogOwner 和 CatOwner 都继承自 AnimalOwner。 AnimalOwner 有一个名为 OwnedAnimal 的 Animal 类型的引用。

下面是示例中的类:

public abstract class Animal
{
   // some properties
}

public class Dog : Animal
{
   // some more properties
}

public class Cat : Animal
{
   // some more properties
}

public class AnimalOwner 
{
   public virtual Animal OwnedAnimal {get;set;}
   // more properties...
}

public class DogOwner : AnimalOwner
{
   // even more properties
}

public class CatOwner : AnimalOwner
{
   // even more properties
}

这些类有适当的 nhibernate 映射,所有属性都是持久的,所有可以延迟加载的东西都是延迟加载的。

应用程序业务逻辑只允许您在 DogOwner 中设置 Dog,在 CatOwner 中设置 Cat。

问题

我有这样的代码:

public void ProcessDogOwner(DogOwner owner)
{
   Dog dog = (Dog)owner.OwnedAnimal;
   ....
}

这个方法可以被许多不同的方法调用,在大多数情况下狗已经在内存中并且一切正常,但很少狗不在内存中 - 在这种情况下我得到一个 nhibernate“未初始化的代理”但是强制转换抛出异常,因为 nhibernate 为 Animal 而不是 Dog 生成代理。

我知道这就是 nhibernate 的工作原理,但我需要在不加载对象的情况下知道类型 - 或者,更准确地说,我需要未初始化的代理作为 Cat 或 Dog 的代理,而不是 Animal 的代理。

约束

  • 我无法更改领域模型,该模型是另一个部门交给我的,我试图让他们更改模型但失败了。
  • 实际模型比示例复杂得多,类之间有很多引用,出于性能原因,使用预先加载或向查询添加连接是不可能的。
  • 我可以完全控制源代码、hbm 映射和数据库架构,并且可以按我想要的方式更改它们(只要我不更改模型类之间的关系)。
  • 我有很多像示例中的方法,但我不想修改所有这些方法。

谢谢,
尼尔

最佳答案

关闭动物类的延迟加载是最简单的。你说它大部分都在内存中。

<class name="Animal" lazy="false">
<!-- ... -->
</class>

作为其变体,您还可以使用no-proxy,参见this post :

<property name="OwnedAnimal" lazy="no-proxy"/>

据我所知,它仅在 AnimalOwner 实际上是代理时才有效。

您可以对动物主人使用泛型,使引用成为一个具体的类。

class AnimalOwner<TAnimal>
{
  virtual TAnimal OwnedAnimal {get;set;}
}

class CatOwner : AnimalOwner<Cat>
{
}

class DogOwner : AnimalOwner<Dog>
{
}

您可以将 DogOwnersCatOwners 映射到单独的表中,并在映射中定义具体的动物类型。

<class name="CatOwner">
  <!-- ... -->
  <property name="OwnedAninal" class="Cat"/>
</class>
<class name="DogOwner">
  <!-- ... -->
  <property name="OwnedAninal" class="Dog"/>
</class>

按照 this blog 中的建议,您对 NHibernate 有点不适应。 . NH实际上是能够返回代理背后的真实对象。这里提出了一个更简单的实现:

    public static T CastEntity<T>(this object entity) where T: class
    {
        var proxy = entity as INHibernateProxy;
        if (proxy != null)
        {
            return proxy.HibernateLazyInitializer.GetImplementation() as T;
        }
        else
        {
            return entity as T;
        }
    }

可以这样使用:

Dog dog = dogOwner.OwnedAnimal.CastEntity<Dog>();

关于c# - 在 NHibernate 中获取正确类型的代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/413237/

相关文章:

c# - Xamarin - 我如何在类外使用列表

c# - 现有类(class)的精简版

c# - 序列化实现 INotifyPropertyChanged 的​​类的实例时出现 SerializationException

c# - 检查 DOM 是否静止

.net - 使用设计器支持将表单作为属性添加到用户控件

c# - 将当前程序集加载到不同的AppDomain中

nhibernate - 没有自动映射 SQL 异常的 Fluent NHibernate,关键字 'User' 附近的语法不正确

nhibernate - 这个错误在nhibernate中意味着什么

c# - 判断 SQL Server 是否可用的最快方法

c# - DataGridView Removing Rows 只移除交替行