简体   繁体   中英

Entity Framework does not translate Linq expression

I have the following data model, and I need to group list of ResponseItem with these conditions:

  • First: Group by ResponseItem.Group
  • Second: Group by ResponseItem.SubGroup , but considering just the most recent one, which means considering the ResponseItem.CreationDate

Code:

    public class ResponseItem
    {
        public string   Group        { get; set; }
        public string   SubGroup     { get; set; }
        public double   Value        { get; set; }
        public DateTime CreationDate { get; set; }
    }
    
    public class GroupedResponseItem
    {
        public string             Group { get; set; }
        public List<ResponseItem> Items { get; set; }
    }

The method is:

public List<GroupedResponseItem> GetGroupedData( IQueryable<ResponseItem> responseItems )
{
    return responseItems
        .OrderByDescending(i => i.CreationDate)
        .GroupBy(i => i.Group)
        .Select(grp => new GroupedResponseItem()
        {
            Group = grp.Key,
            Items = grp
                .GroupBy(i => new { i.SubGroup })
                .Select(grp => grp.First())
                .Select(i => new ResponseItem()
                {
                    SubGroup     = i.SubGroup,
                    CreationDate = i.CreationDate,
                    Value        = i.Value
                }).ToList()
         })
        .ToList();
}

But I get an error:

'The LINQ expression 'ProjectionBindingExpression: 0' 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'

As I mentioned in the title, I'm using Entity Framework on .NET 6.

On the other hand, If I does not consider the second group by, query works fine:

public List<GroupedResponseItem> GetGroupedData(IQueryable<ResponseItem> responseItems)
{
    return responseItems
        .OrderByDescending(i => i.CreationDate)
        .GroupBy(i => i.Group)
        .Select(grp => new GroupedResponseItem()
        {
            Group = grp.Key,
            Items = grp
                .Select(i => new ResponseItem()
                {
                    SubGroup     = i.SubGroup,
                    CreationDate = i.CreationDate,
                    Value        = i.Value
                })
                .ToList()
        })
        .ToList();
}

The culprit seems to be the secondary projection ( Select ) here

.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First()) // <-- (1)
.Select(i => new ResponseItem() // <-- (2)
{
    SubGroup     = i.SubGroup,
    CreationDate = i.CreationDate,
    Value        = i.Value
})
.ToList()

While EF Core 6.0 has improved translation of GroupBy having additional operators on grouping result set (other than key/aggregates, which have natural SQL support), there are still limitations/defects preventing translation of some constructs. In particular, multiple projections.

Shortly, the Select after GroupBy must be the final LINQ operator. Which is kind of sad, since intermediate projection usually helps the translation and is often used to workaround EF Core limitations. But not in this case.

For this particular query, the projection looks redundant since the type of the elements of the group is the same as the projected type, so it could simply be removed

.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First()) // <-- final projection
.ToList()

So this is one of the solutions/workarounds. If you really need a projection, because you are selecting partial columns, or project to a different type, then move it inside the Select after GroupBy :


.GroupBy(i => new { i.SubGroup })
.Select(grp => grp
    .Select(i => new ResponseItem()
     {
         SubGroup = i.SubGroup,
         CreationDate = i.CreationDate,
         Value = i.Value
     })
     .First()
) // <-- final projection
.ToList()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM