在下一个实体框架中选择N + 1 [英] Select N+1 in next Entity Framework

查看:124
本文介绍了在下一个实体框架中选择N + 1的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我听说过关于EF4与NHibernate有关的少数有效投诉之一是EF4在处理懒惰的收藏品方面很差。例如,在一个懒惰的集合中,如果我说:

  if(MyAccount.Orders.Count()> 0 ); 

EF将拉下整个收藏品(如果还没有),而NH将足够聪明发出一个 select count(*)



NH还有一些不错的批量提取来帮助选择n + 1 问题。据我了解,最接近的EF4可以使用Include方法。



EF团队是否放下任何迹象表明这将在下一次迭代中被修复?我知道他们在POCO上工作很辛苦,但这似乎是一个受欢迎的修复。

解决方案

不是N + 1问题。 N + 1问题的例子是这里。 N + 1表示您执行N + 1选择而不是一个(或两个)。在你的例子中,这可能意味着:

  // Lazy加载所有N个订单单选
foreach(var订单在MyAccount.Orders)
{
// Lazy加载单个订单的所有项目=>执行N次
foreach(var orderItem in order.Items)
{
...
}
}
/ pre>

这很容易解决:

  //渴望在单个查询中加载所有订单及其项目
foreach(上下文中的var order).Accounts.Include(Orders.Items)。其中(...))
{
...
}

您的示例看起来对我有效。您的集合显示 IEnumerable ,并执行 Count 操作。集合被延迟加载并且计数在内存中执行。翻译Linq查询到SQL的能力仅在 IQueryable 中可用,表达式树表示查询。但是, IQueryable 表示query =每个访问意味着DB中的新执行,例如检查Count in循环将在每次迭代中执行DB查询。



所以更多的是动态代理的实现。






不加载相关实体的计数将是使用 DbContext 而不是 ObjectContext 而不是使用Code-first CTP5(最终版本将被称为EF 4.1)通过与收集的直接交互。您将不得不使用以下内容:

  int count = context.Entry(myAccount).Collection(a => a。 。订单).Query()计数(); 

查询方法返回准备 IQueryable 这可能是EF运行,如果你使用延迟加载,但你可以进一步修改查询 - 这里我使用计数


One of the few valid complaints I hear about EF4 vis-a-vis NHibernate is that EF4 is poor at handling lazily loaded collections. For example, on a lazily-loaded collection, if I say:

if (MyAccount.Orders.Count() > 0) ;

EF will pull the whole collection down (if it's not already), while NH will be smart enough to issue a select count(*)

NH also has some nice batch fetching to help with the select n + 1 problem. As I understand it, the closest EF4 can come to this is with the Include method.

Has the EF team let slip any indication that this will be fixed in their next iteration? I know they're hard at work on POCO, but this seems like it would be a popular fix.

解决方案

What you describe is not N+1 problem. The example of N+1 problem is here. N+1 means that you execute N+1 selects instead of one (or two). In your example it would most probably mean:

// Lazy loads all N Orders in single select
foreach(var order in MyAccount.Orders)
{
  // Lazy loads all Items for single order => executed N times
  foreach(var orderItem in order.Items)
  {
     ...
  }
}

This is easily solved by:

// Eager load all Orders and their items in single query
foreach(var order in context.Accounts.Include("Orders.Items").Where(...))
{
 ...
}

Your example looks valid to me. You have collection which exposes IEnumerable and you execute Count operation on it. Collection is lazy loaded and count is executed in memory. The ability for translation Linq query to SQL is available only on IQueryable with expression trees representing the query. But IQueryable represents query = each access means new execution in DB so for example checking Count in loop will execute a DB query in each iteration.

So it is more about implementation of dynamic proxy.


Counting related entities without loading them will is already possible in Code-first CTP5 (final release will be called EF 4.1) when using DbContext instead of ObjectContext but not by direct interaction with collection. You will have to use something like:

int count = context.Entry(myAccount).Collection(a => a.Orders).Query().Count();

Query method returns prepared IQueryable which is probably what EF runs if you use lazy loading but you can further modify query - here I used Count.

这篇关于在下一个实体框架中选择N + 1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆