在 NHibernate 中获取正确类型的代理 [英] Getting proxies of the correct type in NHibernate

查看:19
本文介绍了在 NHibernate 中获取正确类型的代理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

领域模型

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

以下是示例中的类:

公共抽象类动物{//一些属性}公共类狗:动物{//更多的属性}公开课猫:动物{//更多的属性}公共类 AnimalOwner{公共虚拟动物拥有的动物 {get;set;}//更多属性...}公共类 DogOwner : AnimalOwner{//更多的属性}公共类 CatOwner : AnimalOwner{//更多的属性}

这些类有适当的 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>

作为一种变体,您还可以使用 no-proxy,请参阅 这篇文章:

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

您可以对动物所有者使用泛型使引用成为具体类.

class AnimalOwner{虚拟 TAnimal OwnedAnimal {get;set;}}CatOwner 类:AnimalOwner{}DogOwner 类:AnimalOwner{}

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

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

你对 NHibernate 有点乱,正如 这个博客.NH实际上能够返回代理背后的真实对象.这里提出了一个更简单的实现:

 public static T CastEntity(this object entity) where T: class{var proxy = entity as INHibernateProxy;如果(代理!= null){返回 proxy.HibernateLazyInitializer.GetImplementation() 作为 T;}别的{将实体返回为 T;}}

可以这样使用:

Dog dog = dogOwner.OwnedAnimal.CastEntity();

I have a problem with uninitialized proxies in nhibernate

The Domain Model

Let's say I have two parallel class hierarchies: Animal, Dog, Cat and AnimalOwner, DogOwner, CatOwner where Dog and Cat both inherit from Animal and DogOwner and CatOwner both inherit from AnimalOwner. AnimalOwner has a reference of type Animal called OwnedAnimal.

Here are the classes in the example:

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
}

The classes have proper nhibernate mapping, all properties are persistent and everything that can be lazy loaded is lazy loaded.

The application business logic only let you to set a Dog in a DogOwner and a Cat in a CatOwner.

The Problem

I have code like this:

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

This method can be called by many diffrent methods, in most cases the dog is already in memory and everything is ok, but rarely the dog isn't already in memory - in this case I get an nhibernate "uninitialized proxy" but the cast throws an exception because nhibernate genrates a proxy for Animal and not for Dog.

I understand that this is how nhibernate works, but I need to know the type without loading the object - or, more correctly I need the uninitialized proxy to be a proxy of Cat or Dog and not a proxy of Animal.

Constraints

  • I can't change the domain model, the model is handed to me by another department, I tried to get them to change the model and failed.
  • The actual model is much more complicated then the example and the classes have many references between them, using eager loading or adding joins to the queries is out of the question for performance reasons.
  • I have full control of the source code, the hbm mapping and the database schema and I can change them any way I want (as long as I don't change the relationships between the model classes).
  • I have many methods like the one in the example and I don't want to modify all of them.

Thanks,
Nir

解决方案

It's easiest to turn off lazy loading for the animal class. You say it's mostly in memory anyway.

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

As a variant of that, you could also use no-proxy, see this post:

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

As far as I can see, it only works when the AnimalOwner actually is a proxy.

OR

You can use generics on the animal owner to make the reference a concrete class.

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

class CatOwner : AnimalOwner<Cat>
{
}

class DogOwner : AnimalOwner<Dog>
{
}

OR

You can map the DogOwners and CatOwners in separate tables, and define the concrete animal type in the mapping.

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

OR

You mess a little around with NHibernate, as proposed in this blog. NH is actually able to return the real object behind the proxy. Here a bit simpler implementation as proposed there:

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

which can be used like this:

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

这篇关于在 NHibernate 中获取正确类型的代理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆