使用ActiveRecord在nHibernate中加载延迟加载的实体

时间:2008-12-19 10:05:30

标签: nhibernate activerecord lazy-loading castle-activerecord aggregateroot

我正在开发一个具有丰富对象模型的项目,该模型具有各种聚合根集合。

我们正在使用 Castle 堆栈(使用ActiveRecord的Monorail到nHibernate)。

我们已将聚合根标记为惰性[ActiveRecord(Lazy = true)],并在我们的存储库上定制了'eager'例程以急切获取对象图。我们使用HQL从我们的root的子集合

定义急切的提取

e.g。如果Account是聚合根(并标记为延迟加载),我们会急切地获取Account .. Order .. Product个实体以获得完整的图表。

到目前为止没有任何惊喜(希望如此)。

现在,如果在上面的示例中,Product也标记为[ActiveRecord(Lazy = true)],这似乎会停止HQL中的eager fetch指令。

有没有人知道如何强制暂时加载延迟加载的子对象

干杯 伊恩

更新

这里有一些示例hql,使用下面的'me.yahoo.com/../1'中的示例,我们使用IMuliQuery在获取多对多关系时重新获得N + 1依赖项。我们还明确使用了多对多映射类。结果我们的hql是:

from Account a 'm eager loading the graph
inner join fetch a.AccountsOrders ao 
inner join fetch ao.Order
from Account a 'm eager loading the graph
inner join fetch a.AccountAddresses aa
inner join fetch aa.Address ad
where a.ID = ?

...所以这会执行2个sql语句并返回所需的最小行集,我们可以将其解析为单个对象图。好的。

但是......如果Address标记为延迟加载(并且Order不是),则访问Order不会触发更多的sql语句,但访问{ {1}}尽管事实上两者都是渴望加载的。

那么为什么上述延迟加载的实体Address不会被上述语句提取?

3 个答案:

答案 0 :(得分:1)

在Account.Order.Product实体上执行“内部联接提取”。所以不是这样的东西(这可能是你已经拥有的东西):

"from Account a inner join fetch a.Order where a.ID = ?"

告诉它同时获取Order.Product:

"from Account a inner join fetch a.Order inner join fetch a.Order.Product where a.ID = ?"

答案 1 :(得分:0)

为什么你想要急切的行为?

ActiveRecord中的所有关系属性都有一个'Lazy ='参数,告诉ActiveRecord延迟加载相关对象。所有除了BelongsTo。 BelongsTo检查依赖对象的ActiveRecord属性是否具有Lazy = true,然后为该对象创建代理,而不是进行选择或连接。

对于延迟加载工作,需要将类实例的所有方法和属性标记为虚拟。这允许ActiveRecord构造动态代理类。

现在,获取完整的性能图可能听起来不错,但实际上它可能更慢。我有三个很好的理由:

1。)BelongsTo有一个Fetch选项来定义相关对象的拉取方式。 FetchEnum.Join强制AR使用Join。 FetchEnum。选择强制AR为每个对象使用单独的select语句。连接速度很慢,我们认为从切换到单个选择可以提高10倍的性能。 Lazy = true + FetchEnum.Select和eager之间的客户端代码没有任何有效差异。

2。)NHibernate进行缓存。如果对象已经缓存在会话或二级缓存中,则可以从那里加载它,避免额外的工作。

3。)如果你没有引用对象图的一部分,你会错过延迟加载的任何好处。你会再做更多的工作。

答案 2 :(得分:0)

来自“NHibernate in Action”,第225页:

  

NHibernate目前限制你急切地抓取一个集合。

这可能解释了获取地址的第二个查询。