Allow providers to customize aggregate lowering of grouped Any/All
维护者通常 2 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 35/100
- Issue 类型
- 功能
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- csharp
调研方向
Start in src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs, especially TryTranslateAggregateMethodCall, TryTranslateQuantifierOverGrouping, and the grouping and predicate processing it uses. Read the grouped-quantifier implementation and the linked provider discussion to understand the proposed hook and null/empty-input semantics. Done means providers can customize grouped Any/All translation while the existing default lowering and unsupported-composition fallback remain available.
由索引模型根据 Issue 内容生成。
描述
Scenario
The PostgreSQL provider would like to translate predicated Any/All over a grouping to PostgreSQL's native bool_or/bool_and aggregates, without introducing new EF.Functions APIs:
context.Items
.GroupBy(i => i.CategoryId)
.Select(g => new
{
g.Key,
Any = g.Any(i => i.Flag),
All = g.All(i => i.Flag)
});
For this unfiltered grouping over a nonnullable boolean column, the desired SQL is:
SELECT i."CategoryId", bool_or(i."Flag") AS "Any", bool_and(i."Flag") AS "All"
FROM "Items" AS i
GROUP BY i."CategoryId"
The same customization is useful when the quantifier appears in ORDER BY or HAVING, including over joined grouping sources. Provider discussion: https://github.com/npgsql/efcore.pg/issues/2394.
This is an extensibility request, not a claim that native boolean aggregates necessarily outperform EF's count-based lowering.
Extensibility gap
The grouped-quantifier lowering added in https://github.com/dotnet/efcore/pull/38937 is implemented in RelationalSqlTranslatingExpressionVisitor:
TryTranslateAggregateMethodCalldispatches groupedAny/Alldirectly toTryTranslateQuantifierOverGrouping.TryTranslateQuantifierOverGroupingis private and constructs the count-based implementation itself.- Its aggregate-translator call uses
Queryable.LongCount, not the original quantifier. Consequently, implementingAny/Allcases in a provider'sIAggregateMethodCallTranslatordoes not allow this customization. Overriding ordinaryLongCounttranslation is not a substitute: the provider needs to distinguish quantifiers from actual counts.
The outer TryTranslateAggregateMethodCall is already protected virtual, but overriding it does not let the provider reuse the existing grouping processing: TryTranslateAsEnumerableExpression is private. Reimplementing that parsing would duplicate EF's handling of grouping-element Where, Select, Distinct, ordering, and unsupported compositions.
Predicate handling also matters: RemapLambda is private and includes shared-type entity expansion, so a provider should ideally be able to reuse that processing as well, rather than just copying the parameter replacement.
Current workaround
A provider-local implementation can intercept predicated Any/All and rewrite them to private, expression-only aggregate markers:
g.Any(p) -> PrivateBoolOr(g.Select(p))
g.All(p) -> PrivateBoolAnd(g.Select(p))
Passing these expressions through the base visitor's custom-aggregate path reuses EF's grouping/filter/selector handling and reaches the provider's aggregate translator. The original operator chain is preserved, and unsupported compositions can fall back to the original quantifier translation.
This avoids copying private EF machinery, but requires synthetic methods and an expression-tree detour solely to reach an otherwise inaccessible translation stage.
Requested extensibility
Provide a protected virtual hook for grouped quantifier translation after the grouping source and quantifier predicate have been processed, but before committing to the generic LongCount lowering. The hook should expose the original quantifier, the EnumerableExpression with its existing filter, and the translated predicate, so providers can return native aggregate SQL or delegate to the default implementation.
Making the existing TryTranslateQuantifierOverGrouping protected virtual would be a useful starting point; if it continues to accept an unprocessed LambdaExpression, the predicate-remapping/translation machinery would also need to be reusable. A hook after predicate translation could avoid exposing those additional helpers.
The provider would remain responsible for its native aggregate's null/empty-input semantics, while retaining EF's existing predicate-free Any() behavior and unsupported-composition fallback. For example, filtered Any must return false on empty input, filtered All must return true, and SQL NULL predicate results must not simply be ignored by bool_and.
- 主要语言
- C#
- 星标
- 14.8k
- 派生
- 3.4k
- 平均合并
- 3 天 18 小时
- 30 天内合并 PR
- 159
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
dotnet/efcore 的其他 Issue
-
customer-reported
难度 4/5 3-5 天 新手友好度 54/100
维护者通常 2 天内回复
-
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 2 天内回复
-
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 2 天内回复
-
Regression in 11.0: replacing an owned instance or re-adding an entity with the same key sets unchanged OnAdd properties to null可能已有人在做 @seragAhmed 今天认领。 未关闭
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 2 天内回复
-
customer-reported
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 2 天内回复
相似的 Issue
-
bug emitter:client:csharp
难度 2/5 1-3 小时 新手友好度 84/100
microsoft/typespec#12572 · 1 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
needs-area-label
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabled未关闭bug
难度 2/5 1-3 小时 新手友好度 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 条评论 ·
维护者通常 1 天内回复
-
area-networking
难度 2/5 1-3 小时 新手友好度 78/100
dotnet/aspnetcore#70545 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 87/100
维护者通常 1 天内回复