NHibernate缩小代理警告 [英] NHibernate narrowing proxy warning

查看:89
本文介绍了NHibernate缩小代理警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在构建一个使用NH进行数据访问的ASP.NET MVC应用程序.使用NH Profiler,我看到了很多警告,例如"WARN:缩小Domain.CaseTask的代理-此操作会中断==.在执行对子表中每个类映射的类的查询时,例如在使用NH Linq提供程序时,我会经常得到这些信息:

We are building an ASP.NET MVC application utilizing NH for data access. Using NH Profiler I see a lot of warnings like "WARN: Narrowing proxy to Domain.CaseTask - this operation breaks ==". I get these very often when executing queries for classes which are mapped in a table per subclass, for example, using the NH Linq provider:

Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of)

CaseTask类从Task继承的地方,触发警告.

where the class CaseTask inherits from Task, triggers the warning.

关于互联网警告的信息很少,并且大多暗示着这是应该忽略的事情……该警告究竟警告了什么?这应该是我应该寻求纠正的东西吗?

Information about the warning in the internet is scarce and mostly hints that this is something to be ignored... What does this warning warn about exactly? Should this be something I should seek to correct?

推荐答案

现实更加复杂.当您使用session.Load加载实体或访问延迟加载的属性时,NHibernate将返回一个代理对象.首次访问代理对象的任何属性时,该代理对象将被水化(数据将从DB中加载).为了实现这一点,NHibernate生成了扩展实体类的代理类,并覆盖了所有属性获取器和设置器.在不使用继承的情况下,此方法非常有效,因为您将无法区分代理类和实体类(代理基本类),例如简单测试proxy is MyEntity将始终有效.

The reality is more complicated. When you load entity using either session.Load or you access a property that is lazy loaded NHibernate returns a proxy object. That proxy object will by hydrated (data will be loaded from DB) when you access any of its properties for the first time. To achieve this NHibernate generates proxy class that extends entity class and overrides all property getters and setters. This works perfectly when inheritance is not used since you will have no way to differentiate between proxy and entity class (proxy base class), e.g. simple test proxy is MyEntity will always work.

现在假设我们有一个Person实体:

Now imagine that we have a Person entity:

class Person {
  // lazy-loaded
  public Animal Pet { get; set; }
}

我们还有Animal类层次结构:

public abstract class Animal { ... }
public class Cat { ... }
public class Dog { ... }

现在假定Pet属性是延迟加载的,当您向NHibernate请求person宠物时,您将获得一个代理对象:

Now assume that Pet property is lazy loaded, when you ask NHibernate for person pet you will get a proxy object:

var pet = somePerson.Pet; // pet will be a proxy

但是,由于Pet是延迟加载属性,NH不会知道它是Cat还是Dog的实例,因此它将尽力而为,并创建扩展Animal的代理.代理将通过pet is Animal的测试,但将通过pet is Catpet is Dog的测试失败.

But since Pet is lazy loaded property NH will not know if it will be instance of a Cat or a Dog, so it will do its best and will create a proxy that extends Animal. The proxy will pass test for pet is Animal but will fail tests for either pet is Cat or pet is Dog.

现在假定您将访问pet对象的某些属性,从而强制NH从DB加载数据.现在,NH会知道您的宠物是Cat,但代理已生成,无法更改. 这将强制NHibernate发出警告,将扩展类型Animalpet的原始代理范围缩小为Cat.这意味着从现在起使用session.Load<Animal>(pet.Id)创建的具有pet.Id的动物的代理对象将从现在开始扩展Cat.这也意味着,由于Cat现在存储为会话的一部分,因此,如果我们加载与第一个共享cat的第二个人,则NH将使用已经可用的Cat代理实例来填充延迟加载的属性.

Now assume that you will access some property of pet object, forcing NH to load data from DB. Now NH will know that your pet is e.g. a Cat but proxy is already generated and cannot be changed. This will force NHibernate to issue a warning that original proxy for pet that extends type Animal will be narrowed to type Cat. This means that from now on proxy object for animal with pet.Id that you create using session.Load<Animal>(pet.Id) will extend Cat from now. This also means that since Cat is now stored as a part of session, if we load a second person that shares cat with the first, NH will use already available Cat proxy instance to populate lazy-loaded property.

后果之一是,对pet的对象引用将不同于通过session.Load<Animal>(pet.Id)获得的引用(在object.ReferencesEqual意义上).

One of the consequences will be that object reference to pet will be different that reference obtained by session.Load<Animal>(pet.Id) (in object.ReferencesEqual sense).

// example - say parent and child share *the same* pet
var pet = child.Pet; // NH will return proxy that extends Animal
pet.DoStuff(); // NH loads data from DB

var parent = child.Parent; // lazy-loaded property
var pet2 = parent.Pet; // NH will return proxy that extends Cat

Assert.NotSame(pet, pet2);

现在这可能会对您造成伤害:

Now when this may cause harm to you:

  1. 当您将实体放入代码中的SetDictionary实体中时,或者使用其他需要Equals/GetHashCode对起作用的结构时.通过提供自定义Equals/GetHashCode实现,可以轻松解决此问题(请参阅:

  1. When you put your entities into Sets or Dictionaryies in your code or if you use any other structure that requires Equals/GetHashCode pair to work. This can be easily fixed by providing custom Equals/GetHashCode implementation (see: http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1)

当您尝试将代理对象强制转换为目标类型时,例如(Cat)pet,但同样有已知的解决方案(例如获取代理的NHibernate中正确的类型)

When you try to cast your proxy object to target type e.g. (Cat)pet, but again there are know solutions (e.g. Getting proxies of the correct type in NHibernate)

所以道理是在域模型中避免尽可能多的继承.

So the moral is to avoid as much as possible inheritance in your domain model.

这篇关于NHibernate缩小代理警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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