我正在阅读关于Nhibernate Lazy Loading http://nhforge.org/wikis/howtonh/lazy-loading-eager-loading.aspx的这篇文章,它使用了类似这样的类结构的例子:
然后该文章显示以下代码:
using (ISession session = SessionFactory.OpenSession())
{
var fromDb = session.Get<Order>(_order.Id);
int sum = 0;
foreach (var line in fromDb.OrderLines)
{
// just some dummy code to force loading of order line
sum += line.Amount;
}
}
然后继续讨论:
n + 1选择语句问题。如果我们访问订单行项目 加载订单后,我们为每一行生成一个select语句 我们访问的项目。
这是我对延迟加载重新编写的行为,即当我第一次获得订单时,订单行集合是订单行集合的代理,然后当我遍历订单行时,每个订单行都按需加载。
然而,这不是我观察到的行为。当我在我的应用程序中尝试这个时会发生什么,当我得到订单时,订单行的集合是代理,但是一旦我使用以下方式访问第一个OrderLine:
fromDb.OrderLines.First()
整个集合被加载到内存中。这对我来说是一个问题,因为集合包含很多项目,我只想更改一个,但是如果我将所有项目加载到内存中并更改一个并尝试保存顺序,我显然会得到很差的性能。
自从我写这篇文章以来,行为改变了吗?我只是误解了延迟加载的工作原理?或者有什么方法可以配置NHibernate只加载它需要的集合中的项目?
答案 0 :(得分:4)
“n + 1选择语句问题。如果我们在加载订单后访问订单行项目,我们会为我们访问的每个订单项生成一个select语句。”不是核心。订单行全部加载在一起,因为这在大多数情况下效率更高。选择N + 1主要是这样的代码:
var orders = session.QueryOver<Order>().List()
var usersWithOrders = orders.Select(o => o.User);
因为您为每个用户选择了1个订单和N个选择(实际上仅因为会话缓存而针对不同的用户)
如果您知道自己拥有大型集合并且只想处理某些集合或需要计数和包含,那么<bag lazy="extra">
/ HasMany(x => x.Lines).ExtraLazyLoad()
会导致集合代理发出查询,包含Count,Contains,this []而不是全部加载。
或者您可以session.QueryOver<OderLines>().Where(line => line.Order == order && ...)
获取您要处理的特定行