NHibernate陷阱:many-to-one关联中的ghost对象
问题
NHibernate的many-to-one关联是支持多态的(理应),然而一不留神,代码就掉进了陷阱。考虑这个类图,OrderLine 有一个Product属性,同时,Product有两个子类。
这个关联的映射:
<many-to-one Name="Product" class="Product" column="ProductId" />
接下来,要为 Food 的订单行执行一点特别的业务逻辑:
OrderLine line = ...; if (line.Product is Food) { // 永远不会执行到这里
}
即使 line 的 Product 是 Food,这个判断也不会成立,针对Food的业务逻辑永远不会执行。
原因
造成这个问题的原因是 NHibernate 默认使用代理对象实现 many-to-one 的延迟加载,程序运行后,类结构实际上是这样的(紫色的类是nhibernate生成的代理类,实际的代理类名称与图中不同):
line对象构造出来以后,他的 Product 属性没有初始化,实际上,它是 ProductProxy 的实例(ghost对象),而 ProductProxy 和 Food 并无转换关系,表达式 (line.Product is Food) 永远为 false。
解决
为了避免 ghost 对象的问题,需要对关联的延迟加载稍稍做一点配置。如果不需要延迟加载,可以禁用:
<many-to-one Name="Product" class="Product" column="ProductId" lazy="false"/>
或者,如果仍然需要延迟加载,可以使用 no-proxy 选项,告诉 NHibernate 仍然延迟加载Product关联,但是不要使用代理对象。
<many-to-one Name="Product" class="Product" column="ProductId" lazy="no-proxy" />