Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for GroupBy entityType #17653

Closed
Tracked by #24106
ares128 opened this issue Sep 6, 2019 · 12 comments · Fixed by #29019
Closed
Tracked by #24106

Support for GroupBy entityType #17653

ares128 opened this issue Sep 6, 2019 · 12 comments · Fixed by #29019
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported ef6-parity type-enhancement
Milestone

Comments

@ares128
Copy link

ares128 commented Sep 6, 2019

Update by @smitpatel

Certain databases support projecting columns after SQL GROUP BY which are neither contained in aggregate nor in grouping key. (SqlServer disallows this). This means that GroupBy entity type when aggregate is applied can be translated to server by grouping by PK and then projecting all the columns for materialization.


Original post:

An InvalidOperationException is throwed when GroupBy on then Include property. But same code works on ef core 2.X.

System.InvalidOperationException: The LINQ expression 'EntityShaperExpression:
    EntityType: Author
    ValueBufferExpression:
        ProjectionBindingExpression: Inner
    IsNullable: False
' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateGroupingKey(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateGroupBy(ShapedQueryExpression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   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.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   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.Query.Internal.EntityQueryable`1.GetEnumerator()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at EFGroupByBug.Program.Main(String[] args) in C:\Users\ares1\source\repos\EFGroupByBug\EFGroupByBug\Program.cs:line 44
   public class Author
    {
        public int Id { get; set; }

        public string Name { get; set; } = default!;
    }

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

        public Author Author { get; set; } = default!;

        public int Price { get; set; }
    }

    public class StoreContext : DbContext
    {
        public DbSet<Author> Authors { get; set; } = default!;

        public DbSet<Book> Books { get; set; } = default!;

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(@"Data Source=test.db;");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (var context = new StoreContext())
                {
                    var array = context.Books.Include(s => s.Author)
                        .GroupBy(s => s.Author)
                        .Select(s => new { author = s.Key, maxPrice = s.Max(p => p.Price) })
                        .ToArray();

                    Console.WriteLine(array.Length);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        }
    }

Current version:
EF Core version: 3.0.0-preview9.19423.6

@smitpatel
Copy link
Contributor

GroupBy entityType cannot be server translated to SQL GROUP BY directly.

@ares128
Copy link
Author

ares128 commented Sep 6, 2019

But same code works on ef core 2.x

@smitpatel
Copy link
Contributor

It evaluated that on client side.

@ares128
Copy link
Author

ares128 commented Sep 6, 2019

Ok I Got it, but i think it can be translated to

SELECT max("b"."Price"), "a"."Id", "a"."Name"
      FROM "Books" AS "b"
      INNER JOIN "Authors" AS "a" ON "b"."AuthorId" = "a"."Id" 
	  GROUP BY "a"."Id";

Can you consider implement this?
Thx

@smitpatel
Copy link
Contributor

It is invalid SQL
Column Authors.Name is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.`

@ares128
Copy link
Author

ares128 commented Sep 6, 2019

image
actually it is, look at the pic

@smitpatel
Copy link
Contributor

Seems like it works on Sqlite. Fails on SqlServer. We will investigate more in which database supports and make a decision. Thanks for pointing to that.

@ares128
Copy link
Author

ares128 commented Sep 6, 2019

thank you

@ares128
Copy link
Author

ares128 commented Sep 6, 2019

For sqlserver, you need add all property in Group by clause.
image

sqlite support this too.
so does mysql

image

image

@GSPP
Copy link

GSPP commented Jun 30, 2020

Pulling over some thoughts from another issue:

Group by supports grouping on scalars and anonymous types. It should also support grouping on an entity type. This should behave the same way as grouping on an anonymous type with the same columns that the entity type has.

This can be translated to SQL by grouping on all columns of that entity type.

Alternatively, grouping can be performed on the primary key columns and all other columns can be re-created through MAX(nonPKColumn).

These translation forms should be possible for all RDBMSes.

This is a LINQ to SQL migration hurdle.

@smitpatel
Copy link
Contributor

Looking at some ef6 generated queries, it seems like we put all columns inside Group by clause. That could be one implementation (may not be most ideal)

@ajcvickers ajcvickers modified the milestones: Backlog, 7.0.0 Nov 11, 2021
This was referenced Sep 7, 2022
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Sep 7, 2022
smitpatel added a commit that referenced this issue Sep 7, 2022
smitpatel added a commit that referenced this issue Sep 7, 2022
smitpatel added a commit that referenced this issue Sep 13, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, 7.0.0-rc2 Sep 14, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0-rc2, 7.0.0 Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported ef6-parity type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants