Как выполнить GroupBy в EF Core 3.1 - PullRequest
0 голосов
/ 27 февраля 2020

Мы обновили наше приложение до Core 3.1, начиная с 2.1. Следующий запрос больше не работает. Что было бы лучшим способом переписать это?

    public async Task<Dictionary<int, CoStatusUpdate>> GetDailyStatusUpdates(int organisationTypeId)
    {
        var dailyUpdates = await _context.CoStatusUpdates
            .Include(x => x.CoStatus)
            .Include(x => x.Company).ThenInclude(x => x.Organisation)
            .GroupBy(p => p.CompanyId)
                .Select(x => new CoStatusUpdate
                {
                    CompanyId = x.Key,
                    Company = new Company() //building new object for the only fields we need otherwise there's way more returned than needed
                    {
                        Organisation = new Organisation()
                        {
                            Name = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.Name,
                            IsDeleted = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.IsDeleted,
                            OrganisationTypeId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.OrganisationTypeId,
                        }
                    },
                    CoStatusUpdateId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatusUpdateId,
                    CoStatusId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatusId,
                    CoStatus = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatus,
                    SubmittedDateTime = x.Max(z => z.SubmittedDateTime)
                }).Where(x => !x.Company.Organisation.IsDeleted
                     && x.Company.Organisation.OrganisationTypeId == organisationTypeId))
            .ToDictionaryAsync(x => x.CompanyId);

        return dailyUpdates;
    }

Ошибка:

{"Выражение LINQ" (GroupByShaperExpression: \ r \ nKeySelector: (f .CompanyId), \ r \ nElementSelector: (EntityShaperExpression: \ r \ n EntityType: CoStatusUpdate \ r \ n ValueBufferExpression: \ r \ n (ProjectionBindingExpression: EmptyProjectionMember) \ r \ n IsNullable: False \ r \ n) ) \ r \ n .FirstOrDefault (y => y.SubmittedDateTime == (GroupByShaperExpression: \ r \ n KeySelector: (f.CompanyId), \ r \ n ElementSelector: (EntityShaperExpression: \ r \ n EntityType: CoStatusUpate Значение ValueBufferExpression: \ r \ n (ProjectionBindingExpression: EmptyProjectionMember) \ r \ n IsNullable: False \ r \ n) \ r \ n) \ r \ n .Max (z => z.SubmittedDateTime)) 'не может быть переведено. Либо переписайте запрос в форме, которую можно перевести, либо переключитесь на оценку клиента явно, вставив вызов либо в AsEnumerable (), AsAsyncEnumerable (), ToList (), либо в ToListAsyn c (). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации. "}

РЕДАКТИРОВАТЬ:

Решение для моего сценария

Хотя я принял первый ответ (он предоставил эквивалент того, что этот запрос уже делал в Core 2.1) Теперь я нашел способ на самом деле выполнить группировку на стороне сервера, которая намного эффективнее.

        var coUpdates = await _context.Companys
            .Where(p=>!p.Organisation.IsDeleted)  
            .Select(p => p.CompanyId)
          //.Distinct() //if you wouldn't already be getting a unique list of id's
            .Select(id => _context.coStatusUpdates
                .Include(u=>u.coStatus)
                .Include(u=>u.Company).ThenInclude(x=>x.Organisation)
                .OrderByDescending(p => p.SubmittedDateTime)  
                .FirstOrDefault(p => p.CompanyId == id))  
            .ToListAsync();

        var coUpdatesDictionary = coUpdates
            .Where(x => x != null)
            .ToDictionary(x=>x.CompanyId);

        return coUpdatesDictionary;

1 Ответ

1 голос
/ 27 февраля 2020

Вам нужно будет разделить это на два разных запроса:

var dailyUpdates = await _context.CoStatusUpdates
            .Include(x => x.CoStatus)
            .Include(x => x.Company)
               .ThenInclude(x => x.Organisation)
            .Where(x => !x.Company.Organisation.IsDeleted
                     && x.Company.Organisation.OrganisationTypeId == organisationTypeId))
            .ToListAsync();

var result = dailyUpdates.GroupBy(p => p.CompanyId)
                .Select(x => new CoStatusUpdate
                {
                    CompanyId = x.Key,
                    Company = new Company() //building new object for the only fields we need otherwise there's way more returned than needed
                    {
                        Organisation = new Organisation()
                        {
                            Name = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.Name,
                            IsDeleted = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.IsDeleted,
                            OrganisationTypeId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).Company.Organisation.OrganisationTypeId,
                        }
                    },
                    CoStatusUpdateId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatusUpdateId,
                    CoStatusId = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatusId,
                    CoStatus = x.FirstOrDefault(y => y.SubmittedDateTime == x.Max(z => z.SubmittedDateTime)).CoStatus,
                    SubmittedDateTime = x.Max(z => z.SubmittedDateTime)
                })
            .ToDictionary(x => x.CompanyId);
...