我需要的是通过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 });
它完美无缺。现在,我希望聚合一个总和而不是访问组的密钥。
这对我来说很棘手。我在想这样的事情:
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)
Intellisense给出签名:
IEnumerable<Document>.Sum<Document>(Func<Document, decimal> selector)
同时:
db.Documents.Sum(a => a.Amount)
我明白了:
IQueryable<Document>.Sum<Document>(Expression<Func<Document, decimal>> selector)
Selector在一个版本中是Func,在另一个版本中是Expression。我不知道如何在Linq Expressions中处理Func。也许Intellisense错了?
汇总来源的表达是我最大的问题。看看:
...b.Sum(c => c.Amount)
我认为b应该是IGrouping(参数表示&#39;选择&#39;),这应该是Sum的源,但不会编译。 我不知道还有什么可以尝试?
以下是最后一个选择表达式的样子:
Expression Select = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(IGrouping<int, Document>), typeof(decimal?) },
GroupBy,
Expression.Lambda(sum, peg));
但是我甚至无法达到这一点,因为失败的总和&#39;表达。
任何指针都会受到赞赏。
问候,
答案 0 :(得分:1)
智能感知是好的。让我们看看:
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
这也意味着GroupBy
和Select
方法来自Queryable
而Sum
来自Enumerable
。
如何在Func<...>
表达式中区分Expression<Func<...>>
和MethodCall
,规则很简单。在这两种情况下,您都使用Expression.Lambda<Func<...>>
来创建Expression<Func<...>>
,然后如果调用需要Func<...>
,则直接传递它,如果方法需要Expression<Func<...>>
,那么请用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);
包裹它{3}}
话虽如此,让我们构建样本查询表达式:
.Object-to-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
}