作为一个简单的例子,我们假设我们有一个名为“myQueryable”的IQueryable,包含3列Id,Value1和Value2,我们编写以下LINQ表达式:
var result = myQueryable.Select(g => new
{
Value1Sum = g.Sum(b => b.Value1),
Value2Sum = g.Sum(b => b.Value2)
});
这将触发2个不同的查询,每个查询一个,然后将它们作为像
之类的对象返回{ Value1Sum = x , Value2Sum = y }
是否可以以这样的方式构建LINQ表达式,即只为两个总和触发一个查询?毕竟它们都是基于相同的数据集来计算的。
为了更清楚,我希望这样的查询:
SELECT SUM(Value1), SUM(Value2) FROM MyTable
但LINQ会生成两个这样的查询(出于安全原因无法发布实际查询):
exec sp_executesql N'SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
SUM([Extent1].[Value1]) AS [A1]
FROM [mo].[MyTable] AS [Extent1]) AS [GroupBy1]
..同样适用于Value2。请注意,即使它调用内部选择“GroupBy1”,也没有任何分组(也在实际查询中)
答案 0 :(得分:2)
首先,获取所需的所有值。
ddepth=-1
使用var values = MyQueryable.Select(item => new { Value1 = item.Value1 , Value2 = item.Value2 })
.ToList();
强制查询执行。 ToList()
仅用于最小化您查询的数据。你也可以使用
Select()
这是您唯一的数据库之旅。
现在您已在本地拥有所有数据,您可以聚合这些值。
var values = MyQueryable.ToList();
之后您有一个元组Tuple<int, int> sums = values.Aggregate(
new Tuple<int, int>(0,0),
(tuple, item) => new Tuple<int, int>(tuple.Item1 + item.Value1, tuple.Item2 + item.Value2));
,其中sums
代表所有sums.Item1
的总和,Value1
分别代表所有sums.Item2
的总和。
Value2
上使用Aggregate
吗?不幸的是,没有。 IQueryable<T>
is not supported in LINQ to Entities,因此无法直接在Aggregate()
上使用它。这就是您首先需要在本地获取数据以便拥有IQueryable<T>
的原因。 然后您可以使用 LINQ to objects 来聚合结果。有关两者之间的区别,请参阅this StackOverflow answer。