我在 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>
{
}
或
您可以将 DogOwners
和 CatOwners
映射到单独的表中,并在映射中定义具体的动物类型。
<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/