Will my LinqToSql execution be deffered if i filter with IEnumerable<T> instead of IQueryable<T>?
我一直使用这些通用的EntityObjectFilters作为"管道和过滤器"方法,从集合中查询具有ID的特定项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static class EntityObjectFilters
{
public static T WithID<T>(this IQueryable<T> qry,
int ID) where T : IEntityObject
{
return qry.SingleOrDefault<T>(item => item.ID == ID);
}
public static T WithID<T>(this IList<T> list,
int ID) where T : IEntityObject
{
return list.SingleOrDefault<T>(item => item.ID == ID);
}
} |
…但我想:"我能通过为所有IEnumerable类型创建一个扩展来简化这一点吗?"所以我想到了这个:
1 2 3 4 5 6 7 8
| public static class EntityObjectFilters
{
public static T WithID<T>(this IEnumerable<T> qry,
int ID) where T : IEntityObject
{
return qry.SingleOrDefault<T>(item => item.ID == ID);
}
} |
现在,虽然这似乎产生了相同的结果,但我想知道,当应用于IQueryables时,表达式树将被传递给linqtosql作为SQL代码进行计算,还是将我的qry首先进行整体计算,然后使用Funcs进行迭代?
我怀疑(根据理查德的回答)后者是真的,这显然是我不想要的。我希望得到相同的结果,但IQueryable的延迟SQL执行带来的额外好处。有人能为我确认实际会发生什么,并就如何工作提供简单的解释吗?
编辑:
我使用的解决方案
1 2 3 4 5 6 7 8
| public static T WithID<T>(this IEnumerable<T> qry,
int ID) where T : DomainBase
{
if (qry is IQueryable<T>)
return ((IQueryable<T>)qry).SingleOrDefault<T>(item => item.ID == ID);
else
return qry.SingleOrDefault<T>(item => item.ID == ID);
} |
不,当qry键入IEnumerable时,它将调用Enumerable.SingleOrDefault而不是Queryable.SingleOrDefault。lambda表达式将转换为委托而不是表达式树,并且不会使用SQL。
注意,SingleOrDefault一开始并不使用延迟执行——它总是立即执行的——但不同之处在于执行查询的地方。几乎可以肯定的是,您希望数据库能够做到这一点。如果您使用简化版本查看日志,您将看到所有结果都被获取了,而使用IQueryable重载,SQL将包含相关的筛选。
- 您是说在第一个示例的第一个函数中,SingleOrDefault甚至不会使用SQL WHERE?
- 是的,这正是乔恩·米恩斯所说的。这样做可能会从表中检索所有数据行并筛选客户端。这对性能非常不利。
- 等等:他说SingleOrDefault不使用延迟执行,但是如果是Queryable.SingleOrDefault,它可以在SQL中查询。这似乎表明,第一个示例中的第一个函数将使用SQL WHERE。同意?
- @Cottsak:第一个函数应该在SQL中使用where,是的。使用您的第二个代码片段,over IEnumerable不会使用where。
- @乔恩:参考编辑:这是一个可以接受的折衷方案,满足单一扩展方法的要求吗?
- @科特萨克:是的-有点难看,但它让打电话的人觉得简单一些。一个问题是,您不能轻易地强制它在进程中完成;通常您会考虑使用AsEnumerable强制查询的其余部分在进程中执行,但在这种情况下不起作用。
- 是的,这不是很有吸引力的演员装束。在选择单个项目时,我不确定强制使用代理的选项是否有任何优势。我可以理解范围的情况-很好的例子是表达式逻辑无法转换为SQL。在这种情况下,"进行中"选项为什么对我有利?
- @科特萨克:老实说,我认为不会。当你开始做这类事情的时候,这是一个更普遍的关注点——如果你将来做类似的事情,这是值得注意的。
- 好建议。谢谢
- @乔恩,我想我刚发现一只虫子。通过像我的解决方案示例中那样扩展IEnumerable,我是否不强制qry在方法中始终被强制强制转换为IEnumerable?通过这样做(投射到一个派生程度较低的类型),永远无法到达if条件的第一部分?
- @不,因为"is"处理对象的执行时间类型,而不是编译时间类型。
- @乔恩:在这种情况下,您对预编译(如:lanitdev.wordpress.com/2010/01/06/&hellip;)的看法是什么?我好像不知道是否有好处。
- @科特萨克:老实说,我没有足够的经验。