2012-10-29 102 views
1

对象表达式的Linq返回一个对象,该对象在枚举时产生序列中的元素。通常,延迟的LINQ-to-Object方法充当流水线,因此序列中的每个元素都会在处理下一个元素之前流经处理管道。对Linq-to-Entities查询操作的Linq-to-Objects查询存在一些混淆

一个)但如果LINQ到对象查询上的LINQ到实体查询的结果进行操作,那么当foreach试图遍历search,并再次各元件流过整个处理序列的下一个元素被处理之前(换句话说,是从DB检索的序列中的第一个元素,然后由Enumerable.Where处理,然后由Enumerable.SelectMany处理,然后才从DB检索下一个元素),或者是一次从DB检索的整个元素集(当foreach尝试从序列中读取第一个元素),只有这些元素开始流经Linq-to-Objects运算符的处理管道?

 var search = context.Contacts.AsEnumerable(). 
      Where(s => s.ContactID > 10).SelectMany(s => s.Address); 

谢谢

回答

1

首先context.Contacts是由表达式转换(从IQueryable)到SQL的EF查询供应商处理。

然后,通过AsEnumerable,与EF查询提供程序的链接被破坏,之后的任何内容都是linq到对象,从前面的语句处理结果集。

但是,由于Contact.Address是一个延迟加载的集合,因此每个传递管道的Contact都会发出一个新查询以填充它。这是可能的,因为EF使用Contact的代理类型,该代理类型通过一个通过EF查询提供程序运行查询的getter来覆盖Address

正如您可能知道的那样,当您清除AsEnumerable时,整个语句会变成Expression树,EF将转换为一条SQL语句。

+0

1)因此,整个集合一次从DB中检索,只有Enumerable操作符才开始处理元素? 2)即使使用这个查询,Enumerable运算符是否正确,只有当所有的Enumerable运算符完成处理前面的元素时,它才会开始处理特定的元素? – carewithl

+1

db查询运行并在'AsEnumerable'之后,任何linq语句链被评估为一个管道。但必须清楚的是,整个语句(包括db部分)只有在实际枚举时才会执行。 –

+0

我可以问一下“作为一条管线”是什么意思吗? – carewithl