我们正在构建一个使用NH进行数据访问的ASP.NET MVC应用程序.使用NH Profiler我看到很多警告,例如"WARN:将代理缩小到Domain.CaseTask - 此操作中断==".在对每个子类的表中映射的类执行查询时,我经常得到这些,例如,使用NH Linq提供程序:
Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of)
Run Code Online (Sandbox Code Playgroud)
CaseTask类从Task继承的地方,触发警告.
关于互联网上警告的信息很少,并且大多暗示这是可以忽略的......这个警告到底有什么警告?这应该是我应该寻求纠正的吗?
现实更加复杂。当您使用或者加载实体session.Load
或访问延迟加载的属性时,NHibernate将返回一个代理对象。首次访问代理对象的任何属性时,该代理对象将被水化(数据将从DB中加载)。为了实现这一点,NHibernate生成了代理类,该代理类扩展了实体类并覆盖了所有属性的获取器和设置器。当不使用继承时,此方法非常有效,因为您将无法区分代理类和实体类(代理基类),例如简单的测试proxy is MyEntity
将始终有效。
现在假设我们有一个Person实体:
class Person {
// lazy-loaded
public Animal Pet { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我们还有Animal
类层次结构:
public abstract class Animal { ... }
public class Cat { ... }
public class Dog { ... }
Run Code Online (Sandbox Code Playgroud)
现在假设该Pet
属性是延迟加载的,当您向NHibernate请求person宠物时,您将获得一个代理对象:
var pet = somePerson.Pet; // pet will be a proxy
Run Code Online (Sandbox Code Playgroud)
但是由于Pet
NH是延迟加载的属性,它不会知道它是a Cat
还是a的实例Dog
,因此它会尽力而为,并且创建一个扩展的代理Animal
。代理会通过测试pet is Animal
,但会失败试验两种pet is Cat
或pet is Dog
。
现在,假设您将访问pet
对象的某些属性,强制NH从DB加载数据。现在,NH将知道您的宠物是例如,Cat
但是代理已经生成并且无法更改。这将迫使NHibernate发出警告,pet
指出该扩展类型的原始代理Animal
将缩小为type Cat
。这意味着从现在开始pet.Id
,您使用的动物代理对象将从现在开始session.Load<Animal>(pet.Id)
扩展Cat
。这也意味着,由于Cat
现在存储为会话的一部分,因此,如果我们加载与第一个共享cat的第二个人,则NH将使用已经可用的Cat
代理实例来填充延迟加载的属性。
结果之一就是对象引用pet
将不同于session.Load<Animal>(pet.Id)
(从object.ReferencesEqual
某种意义上)获得的引用。
// 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);
Run Code Online (Sandbox Code Playgroud)
现在,当这可能对您造成伤害时:
当您在代码中将实体放入Set
s或Dictionary
ies时,或者使用任何其他需要结Equals/GetHashCode
对工作的结构时。通过提供自定义Equals/GetHashCode
实现,可以轻松解决此问题(请参阅:http : //www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html? page = 1)
当您尝试将代理对象强制转换为目标类型时,例如(Cat)pet
,但是同样存在已知的解决方案(例如,在NHibernate中获取正确类型的代理)
因此,道理是在域模型中尽可能避免继承。
此警告是关于具有子类属性或字段的类。IE:
public class Animal
{
public int Id {get;set;}
}
public class Cat : Animal
{
public int Weight {get;set;}
}
public class Person
{
public Cat Pet {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
NHibernate 在加载 person 实体时会感到不安,因为它不想为您进行转换,因为行为变得不可预测。除非您告诉 NHibernate 如何处理 Equals(以及其他逻辑),否则它不会知道如何自行进行比较。
纠正这个问题的基本想法是让 NHibernate 将基类对象放入图中,然后处理转换(请注意,此设置将使用一些略有不同的映射 - 我这样做是为了简化代码,但显然可以完成通过将属性保留为完整的 getter/setter):
public class Animal
{
public int Id {get;set;}
}
public class Cat : Animal
{
public int Weight {get;set;}
}
public class Person
{
private Animal _pet;
public Cat Pet {
get{return _pet as Cat;}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7731 次 |
最近记录: |