gpt4 book ai didi

c# - 通过 Linq.Expressions 和 Lambda 进行 GroupBy 查询

转载 作者:行者123 更新时间:2023-12-03 09:13:26 25 4
gpt4 key购买 nike

我需要的是通过 Linq.Expressions 表示此查询:

db.Documents.GroupBy(a => 1).Select(b => b.Sum(c => c.Amount) });

这是我到目前为止所拥有的:

IQueryable<Document> data = db.Documents;

ParameterExpression pe = Expression.Parameter(typeof(Document), "doc");

Expression groupBy = Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { typeof(Document), typeof(int) },
data.Expression,
Expression.Lambda(Expression.Constant(1), pe));

ParameterExpression peg = Expression.Parameter(typeof(IGrouping<int, Document>), "group");

Expression select = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(IGrouping<int, Document>), typeof(int) },
groupBy,
Expression.Lambda(Expression.Property(peg, "Key"), peg));

foreach (var item in data.Provider.CreateQuery(select)) { ... }

这是实现:

db.Documents.GroupBy(a => 1).Select(b => b.Key });

而且效果非常好。现在,我想聚合一个总和,而不是访问组的 key 。

这对我来说是棘手的地方。我在想这样的事情:

ParameterExpression pe1 = Expression.Parameter(typeof(Document), "other");

Expression sum = Expression.Call(
typeof(Queryable),
"Sum",
new Type[] { typeof(Document) },
peg,
Expression.Lambda(Expression.Property(pe1, "Amount"), pe1));

此外,对于

中的 Sum 函数
...b.Sum(c => c.Amount)

智能感知给出签名:

IEnumerable<Document>.Sum<Document>(Func<Document, decimal> selector)

同时:

db.Documents.Sum(a => a.Amount)

我得到:

IQueryable<Document>.Sum<Document>(Expression<Func<Document, decimal>> selector)

选择器在一种版本中是 Func,在另一种版本中是 Expression。我不知道如何处理 Linq 表达式中的 Func。也许智能感知是错误的?

聚合源的表达式是我最大的问题。通过查看:

...b.Sum(c => c.Amount)

我会假设 b 应该是 IGrouping(“select”的 ParameterExpression),并且这应该是 Sum 的源,但这不会编译。我不知道还能尝试什么?

最后一个选择表达式应如下所示:

Expression Select = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(IGrouping<int, Document>), typeof(decimal?) },
GroupBy,
Expression.Lambda(sum, peg));

但由于“sum”表达式失败,我什至无法达到这一点。

如有任何指点,我们将不胜感激。

问候,

最佳答案

智能感知没问题。让我们看看:

db.Documents.GroupBy(a => 1).Select(b => b.Sum(c => c.Amount) });

(1) db.Documents类型是IQueryable<Document>
(2)a类型是Document
(3)db.Documents.GroupBy(a => 1)类型是IQueryable<IGrouping<int, Document>>
(4)b类型是IGrouping<int, Document> , which in turn is IEnumerable<Document>
(5)c类型是Document

这也意味着GroupBySelect方法来自QueryableSum来自 Enumerable .

那如何区分​​Func<...>呢?和Expression<Func<...>>里面MethodCall表达式,规则很简单。在这两种情况下,您都使用 Expression.Lambda<Func<...>>创建Expression<Func<...>> ,然后如果调用需要 Func<...>你直接传递它,如果该方法期望 Expression<Func<...>>然后你用 Expression.Quote 包裹它.

话虽如此,让我们构建示例查询表达式:

var query = db.Documents.AsQueryable();
// query.GroupBy(a => 1)
var a = Expression.Parameter(typeof(Document), "a");
var groupKeySelector = Expression.Lambda(Expression.Constant(1), a);
var groupByCall = Expression.Call(typeof(Queryable), "GroupBy",
new Type[] { a.Type, groupKeySelector.Body.Type },
query.Expression, Expression.Quote(groupKeySelector));
// c => c.Amount
var c = Expression.Parameter(typeof(Document), "c");
var sumSelector = Expression.Lambda(Expression.PropertyOrField(c, "Amount"), c);
// b => b.Sum(c => c.Amount)
var b = Expression.Parameter(groupByCall.Type.GetGenericArguments().Single(), "b");
var sumCall = Expression.Call(typeof(Enumerable), "Sum",
new Type[] { c.Type },
b, sumSelector);
// query.GroupBy(a => 1).Select(b => b.Sum(c => c.Amount))
var selector = Expression.Lambda(sumCall, b);
var selectCall = Expression.Call(typeof(Queryable), "Select",
new Type[] { b.Type, selector.Body.Type },
groupByCall, Expression.Quote(selector));
// selectCall is our expression, let test it
var result = query.Provider.CreateQuery(selectCall);

关于c# - 通过 Linq.Expressions 和 Lambda 进行 GroupBy 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39728898/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com