在NHibernate 3.0 Cookbook中,有一个基本实体类型的示例实现.平等是这样实现的:
public abstract class Entity<TId> { public virtual TId Id { get; protected set; } public override bool Equals(object obj) { return Equals(obj as Entity<TId>); } private static bool IsTransient(Entity<TId> obj) { return obj != null && Equals(obj.Id,default(TId)); } private Type GetUnproxiedType() { return GetType(); } public virtual bool Equals(Entity<TId> other) { if (other == null) return false; if (ReferenceEquals(this,other)) return true; if (!IsTransient(this) && !IsTransient(this) && Equals(Id,other.Id)) { var otherType = other.GetUnproxiedType(); var thisType = GetUnproxiedType(); return thisType.IsAssignableFrom(otherType) || otherType.IsAssignableFrom(thisType); } return false; } }
GetUnproxiedtype()方法的原因是:有一个抽象基类Product,一个继承自Product的具体类Book,以及NHibernate用于延迟加载的动态代理类ProductProxy.如果ProductProxy表示书和具体书具有相同的Ids,则应将其视为相等.但是我真的不明白为什么在这种情况下,在ProductProxy实例上调用GetType()返回Product,以及它如何帮助.有任何想法吗?
解决方法
我实际上是去写这本书的作者的这个代码.原来这是由于代理包装的工作原理.这是他的回应:
“如果你不明白代理框架如何工作,这个想法似乎是神奇的.
当NHibernate返回一个用于延迟加载的代理时,它返回一个继承自实际类型的代理实例.有几个成员我们可以访问,而不强制从数据库加载.其中包括代理的Id属性或字段GetType(),在某些情况下为Equals()和GetHashCode().访问任何其他成员将强制从数据库加载.
当这种情况发生时,代理创建一个内部实例.因此,例如,客户端的延迟加载实例(CustomerProxy102987098721340978)在加载时将在内部创建一个新的Customer实例,其中包含数据库中的所有数据.代理然后做这样的事情:
public overrides string Name { get { return _loadedInstance.Name; } set { _loadedInstance.Name = value; } }
顺便提一句,这是一个重要的事情,它要求所有的东西都在允许延迟加载的实体上进行虚拟化.
因此,所有对代理服务器上的Name属性的调用都将转发给具有实际数据的内部Customer实例.
GetUnproxiedType()利用这一点.代理上对GetType()的简单调用将返回typeof(CustomerProxy02139487509812340).调用GetUnproxiedType()将被转发到内部客户实例,内部客户实例将返回typeof(Customer).