【发布时间】:2011-11-26 23:23:25
【问题描述】:
我的应用程序根据用户指定的过滤条件使用 PredicateBuilder 构建动态 LINQ 查询(另外:查看此link 以获得最佳 EF PredicateBuilder 实现)。问题是这个查询通常需要很长时间才能运行,我需要这个查询的结果来执行其他查询(即将结果与其他表连接)。如果我正在编写 T-SQL,我会将第一个查询的结果放入临时表或表变量中,然后围绕它编写其他查询。我想从第一个查询中获取一个 ID 列表(例如,List<Int32> query1IDs),然后执行以下操作:
var query2 = DbContext.TableName.Where(x => query1IDs.Contains(x.ID))
这在理论上可行;但是,query1IDs 中的 ID 数量可以是 数百 或 数千(并且 LINQ 表达式 x => query1IDs.Contains(x.ID) 被转换为 T-SQL“IN”语句, 这显然是不好的) 并且 TableName 中的行数在 百万 中。有没有人对处理这种情况的最佳方法有任何建议?
编辑 1: 进一步说明我在做什么。
好的,我正在构建我的第一个查询 (query1),它只包含我感兴趣的 ID。基本上,我将使用 query1 来“过滤”其他表。注意:我不在 LINQ 语句的末尾使用ToList() ---此时查询不执行并且否 结果发送给客户端:
var query1 = DbContext.TableName1.Where(ComplexFilterLogic).Select(x => x.ID)
然后我使用 query1 并使用它来过滤另一个表 (TableName2)。我现在将ToList() 放在此语句的末尾,因为我想执行它并将结果带给客户端:
var query2 = (from a in DbContext.TableName2 join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
然后我使用 query1 并重新使用它来过滤另一个表 (TableName3),执行它并将结果带到客户端:
var query3 = (from a in DbContext.TableName3 join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
我可以继续对任意数量的查询执行此操作:
var queryN = (from a in DbContext.TableNameN join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
问题:query1 需要 很长 时间来执行。当我执行 query2、query3...queryN、query1 被执行 (N-1) 次...这不是一种非常有效的做事方式(特别是因为 query1 没有改变)。如前所述,如果我在编写 T-SQL,我会将 query1 的结果放入一个临时表中,然后在后续查询中使用该表。
编辑 2:
我将把回答这个问题的功劳归功于 Albin Sunnanbo 的评论:
当我想在其他几个查询中重用一个繁重的查询时遇到类似的问题时,我总是回到在每个查询中创建一个连接的解决方案,并投入更多精力来优化查询执行(主要是通过调整我的索引)。
我认为这确实是 Entity Framework 所能做的最好的事情。最后,如果性能真的很差,我可能会接受 John Wooley 的建议:
在这种情况下,针对返回多个结果的存储过程并使用内部临时表下降到本机 ADO 可能是此操作的最佳选择。将 EF 用于应用程序的其他 90%。
感谢所有评论这篇文章的人...感谢大家的意见!
【问题讨论】:
-
如果要将查询直接保存在服务器上,则需要避免将初始 IQueryable 转换为 IEnumerable(通过 ToList/ToArray/AsEnumerable/等)。 EF 应该在连接的表达式树上正确地组合查询。您不能通过 IEnumerable 使用 Contains 传递超过 2000 个参数。为什么 query1IDs 不是 IQueryable?
-
嗨,吉姆,感谢您的 cmets。请参阅我原来的问题中的编辑 1,以更清楚地了解我正在尝试做什么。问题不在于将查询保留在服务器上(出于您给出的原因,我当然想这样做)...问题是我不想继续执行 query1 因为它非常慢。
-
可以将临时表与 Linq To Entities 一起使用。我已经用 Linq2Sql 做了这个,但是对 Linq To Entities 的了解还不够,不能说是否可以做类似的事情。有关详细信息,请参阅我对这个问题的回复stackoverflow.com/questions/6122185/…。
-
你好 sgmoore!是的!这是我想用 Linq2Entities 做的事情......但是,我不确定它是否可能。我将对此进行进一步调查。如果在实体框架中可以的话,我认为实现会稍微复杂一些。听起来我必须即时编辑 *.edmx 文件——这可能是不可能的。有人对如何在 Linq2Entities 中实现 sgmoore 的想法有任何想法吗?
-
@sgmoore 选项的缺点是它在高并发环境中不起作用。它还需要数据库中的管理员(创建表/删除表)权限,这通常是一个安全漏洞。对于 L2S,我可以推荐使用返回 IMultipleResults 的存储过程,但 EF 还不支持这些。在这种情况下,针对返回多个结果的存储过程并使用内部临时表下降到本机 ADO 可能是此操作的最佳选择。将 EF 用于应用程序的其他 90%。
标签: c# entity-framework c#-4.0 entity-framework-4 entity-framework-4.1