Skip to content

Aggregate function on owned type fails in EF8 #36990

Closed

Description

@DnikitaA

Bug description

Code below works in EF Core 6.0. But failed on EF Core 8.0.

I found the same issue #29201, but it was closed. The solution that was proposed only works with the Sum method.

Your code

using Microsoft.EntityFrameworkCore;

namespace GroupOwnedFields;

[Owned]
public class Period
{
    public DateTime Begin { get; set; }

    public DateTime End { get; set; }
}


public class Point
{
    public int Id { get; set; }

    public int OwnerId { get; set; }

    public DateTime DateTime { get; set; }

    public required Period Period { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<Point> Points { get; set; }

    public AppDbContext()
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=Test;Persist Security Info=True;User ID=test;Password=test");
        optionsBuilder.EnableSensitiveDataLogging();
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        using var context = new AppDbContext();
        var query = context.Points
            .GroupBy(e => e.OwnerId)
            .Select(g => new
            {
                TotalCount = g.Count(),
                PastCount = g.Count(e => e.Period.End < DateTime.UtcNow)
            });
        var queryText = query.ToQueryString();
    }
}

Stack traces

System.InvalidOperationException
  HResult=0x80131509
  Message=Translation of 'EF.Property<Period>(StructuralTypeShaperExpression: 
    GroupOwnedFields.Point
    ValueBufferExpression: 
        ProjectionBindingExpression: EmptyProjectionMember
    IsNullable: False
, "Period")' failed. Either the query source is not an entity type, or the specified property does not exist on the entity type.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMember(MemberExpression memberExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.ProcessPredicate(EnumerableExpression enumerableExpression, LambdaExpression lambdaExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TryTranslateAggregateMethodCall(MethodCallExpression methodCallExpression, SqlExpression& translation)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.TryTranslateAggregateMethodCall(MethodCallExpression methodCallExpression, SqlExpression& translation)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateProjection(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitNew(NewExpression newExpression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToQueryString(IQueryable source)
   at GroupOwnedFields.Program.Main(String[] args) in D:\Projects\Git\GroupOwnedFields\GroupOwnedFields\Program.cs:line 52

Verbose output


EF Core version

8.0.21

Database provider

No response

Target framework

.NET 8.0

Operating system

No response

IDE

No response

Activity

  1. added theissue type on Oct 17, 2025
  2. cincuranet commented on Oct 17, 2025

    @cincuranet
    Contributor

    Repros on main as well.

  3. added this to the 11.0.0 milestone on Oct 31, 2025
  4. modified the milestones: 11.0.0, Backlog on Jun 9, 2026
  5. QHarshil commented on Sep 3, 2026

    @QHarshil
    Contributor

    The binding failure comes from aggregate lambdas over a grouping being remapped onto the grouping element in RelationalSqlTranslatingExpressionVisitor, which doesn't expand owned navigations, so the navigation never binds. #29201 made that non-fatal for aggregate selectors, which then fall back to a correlated subquery per aggregate; Count with a predicate goes through ProcessPredicate and still throws.

    I have a fix that runs the existing shared-type entity expansion over the remapped lambda body. It also covers #37778, #29593 and #31062, which have the same cause. I can open a PR if that approach looks right.

  6. QHarshil commented on Sep 4, 2026

    @QHarshil
    Contributor

    Implementation and regression tests are on my fork: https://github.com/QHarshil/efcore/tree/query/owned-navigations-in-groupby-aggregates

    The change expands owned navigations on the lambda after it is remapped onto the grouping element in RelationalSqlTranslatingExpressionVisitor, reusing the expansion the queryable translator already runs elsewhere. A dependent mapped to its own table is left unexpanded, since expanding it would add an owner join and the dependent's key as an identifier to a query that has already been grouped; those queries keep the translation they have today.

    It covers #36990, #37778, #29593 and #31062: JSON-mapped, table-splitting and entity-splitting owned types, owned types nested in those, owned collections, aggregate selectors, Count predicates, Where over the grouping, and orderings.

    One design question before I open a PR. #38668 handled reference navigations by lifting into pre-GroupBy joins in navigation expansion; this does the owned case in the relational translator, after grouping is applied. Is that the layer you want it in? I would rather move it now than after review.

  7. added 2 commits that reference this issue on Sep 4, 2026
    cdd7aad
    0a8e61d
  8. modified the milestones: Backlog, 12.0.0 on Sep 10, 2026
  9. added a commit that references this issue on Sep 10, 2026
    49cee0d
  10. added a commit that references this issue on Sep 25, 2026
    f3ff96c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions