重用LINQ查询会导致另一个LINQ查询,而无需重新查询数据库

我的情况是我的应用程序根据用户指定的过滤条件使用PredicateBuilder构建动态LINQ查询( 除了:查看此链接以获得最佳EF PredicateBuilder实现 )。 问题是这个查询通常需要很长时间才能运行,我需要此查询的结果来执行其他查询(即,将结果与其他表连接)。 如果我正在编写T-SQL,我会将第一个查询的结果放入临时表或表变量中,然后围绕它写出我的其他查询。 我想从第一个查询中获取ID列表(例如, List query1IDs ),然后执行以下操作:

var query2 = DbContext.TableName.Where(x => query1IDs.Contains(x.ID))

这将在理论上起作用; 但是, query1IDs的ID query1IDs可以是数百数千 (并且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的建议:

这可能是这样一种情况:针对存储的proc返回本机ADO返回多个结果并使用内部临时表可能是此操作的最佳选择。 将EF用于其他90%的应用。

感谢所有评论过这篇文章的人……感谢大家的投入!

如果TableName的大小不是太大,无法加载您使用的整个表

 var tableNameById = DbContext.TableName.ToDictionary(x => x.ID); 

获取整个表并自动将其放在ID为关键的本地Dictionary

另一种方法是使用.ToList()强制LINQ评估,在获取整个表的情况下,使用Linq2Objects Where本地执行Where部分。

 var query1Lookup = new Hashset(query1IDs); var query2 = DbContext.TableName.ToList().Where(x => query1IDs.Contains(x.ID)); 

编辑:
从列表中的一个查询存储ID:s列表并将该列表用作另一个查询中的filter通常可以重写为连接。
当我在一些繁重的查询中遇到类似的问题,我想在其他几个查询中重用时,我总是回到在每个查询中创建连接的解决方案,并且更加努力地优化查询执行(主要是通过调整我的索引)。

由于您正在运行结果的后续查询,请执行第一个查询并将其用作SQL Server上的View,将视图添加到上下文中,并针对视图构建LINQ查询。

您是否考虑过根据本文撰写查询(使用装饰器设计模式):

使用装饰器模式组合LINQ查询

前提是,不是枚举你的第一个(非常常见的)查询,而是基本上使用装饰器模式来生成一个IQueryable链,它是查询1和查询N的结果。这样你总是执行查询的过滤forms。

希望这可能有所帮助