我可以通过修改IQueryable来形成LINQ查询吗?

时间:2017-08-04 11:33:25

标签: c# sql .net linq linq-to-sql

我有一个很大的LINQ查询,导致SQL查询效率低下。我非常确定我可以通过调整查询来优化它(如Scott Gu的this blog post和Eugene Prystupa的this excellent blog post中提到的那样,他们称之为"暗示&# 34。)

但是,此查询是重要的遗留代码,因此我宁愿不触及查询本身。是否可以通过修改生成的IQueryable来形成LINQ查询?

例如,我们假设低效查询位于GetOrders,它将查询结果作为IQueryable<Order>返回。我可以塑造IQueryable结果吗? E.g:

var result = GetOrders();

result = result.Select(o =>
    new { o, o.Id, o.Customer, o.Payment })
    .AsEnumerable()
    .Select(o => o.o);

注意最后选择,即返回Order个对象。 (有关此gem的信息,请参阅Prystupa's blog。)此示例整形的要点是让LINQ2SQL(或实体框架)将Customer表与Customer和Payment连接起来。查询订单后原始查询将查询这些表n次,其中n是订单数。

2 个答案:

答案 0 :(得分:0)

通过实验,我发现这确实是可能的。只要查询仍然是LINQ-to-SQL或LINQ-to-Entities而不是LINQ-to-Objects,您仍然可以对查询进行整形。 (当您通过调用ToListAsEnumerable之类的内容将结果集放入内存时,查询将变为LINQ-to-Objects。)

一个很大的警告:你只能在一对一的关系中获得SQL连接。如果在Select的匿名对象中包含一对多或多对多子项,则生成的SQL仍将对子项的表进行n个额外查询,其中n 1}}是记录的数量。这让我绊倒了很长时间,并让我觉得塑造根本不做任何事情。

我仍然希望能找到关于此事的官方文件。

答案 1 :(得分:-1)

我相信,正如博客文章所指出的,你必须做AsEnumerable,否则中间选择将在查询中进行优化:

var result = GetOrders();

result = result.Select(o => new { o, o.Id, o.Customer, o.Payment })
               .AsEnumerable()
               .Select(o => o.o);