如何在 EF Core 3.1 中执行 GroupBy
How to perform GroupBy in EF Core 3.1
我们已将应用程序从 2.1 升级到 Core 3.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;
}
错误是:
{"The LINQ expression '(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)\r\n .FirstOrDefault(y => y.SubmittedDateTime == (GroupByShaperExpression:\r\n KeySelector: (f.CompanyId), \r\n ElementSelector:(EntityShaperExpression: \r\n EntityType: CoStatusUpdate\r\n ValueBufferExpression: \r\n (ProjectionBindingExpression: EmptyProjectionMember)\r\n IsNullable: False\r\n )\r\n )\r\n .Max(z => z.SubmittedDateTime))' 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."}
编辑:
我的场景的解决方案
虽然我接受了给出的第一个答案(它提供了与此查询在 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;
您需要将其拆分为两个不同的查询:
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);
我们已将应用程序从 2.1 升级到 Core 3.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;
}
错误是:
{"The LINQ expression '(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)\r\n .FirstOrDefault(y => y.SubmittedDateTime == (GroupByShaperExpression:\r\n KeySelector: (f.CompanyId), \r\n ElementSelector:(EntityShaperExpression: \r\n EntityType: CoStatusUpdate\r\n ValueBufferExpression: \r\n (ProjectionBindingExpression: EmptyProjectionMember)\r\n IsNullable: False\r\n )\r\n )\r\n .Max(z => z.SubmittedDateTime))' 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."}
编辑:
我的场景的解决方案
虽然我接受了给出的第一个答案(它提供了与此查询在 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;
您需要将其拆分为两个不同的查询:
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);