如何使用 EF 3.1 Entity Framework GroupBy 中每个组的前 N 行
How to select top N rows for each group in a Entity Framework GroupBy with EF 3.1
我需要在 table 和 entity framework 中获取每个组的前 10 行。
基于 SO 上的其他解决方案,我尝试了两件事:
var sendDocuments = await context.Set<DbDocument>
.Where(t => partnerIds.Contains(t.SenderId))
.GroupBy(t => t.SenderId)
.Select(t => new
{
t.Key,
Documents = t.OrderByDescending(t2 => t2.InsertedDateTime).Take(10)
})
.ToArrayAsync();
错误:
System.InvalidOperationException: 'The LINQ expression
'(GroupByShaperExpression: KeySelector: (d.SenderId),
ElementSelector:(EntityShaperExpression:
EntityType: DbDocument
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False ) )
.OrderByDescending(t2 => t2.InsertedDateTime)' 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().
和
var sendDocuments2 = await context.Set<DbDocument>
.Where(t => partnerIds.Contains(t.SenderId))
.GroupBy(t => t.SenderId)
.SelectMany(t => t.OrderByDescending(t2 => t2.InsertedDateTime).Take(10))
.ToArrayAsync();
错误:
System.InvalidOperationException: 'Processing of the LINQ expression
't => t
.OrderByDescending(t2 => t2.InsertedDateTime)
.AsQueryable()
.Take(10)' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core.
还有其他想法吗?
更新(EF Core 6.0):
EF Core 6.0 增加了对转换 GroupBy
结果集投影的支持,因此获取 (key, items) 的原始代码现在可以正常工作,即
var query = context.Set<DbDocument>()
.Where(e => partnerIds.Contains(e.SenderId))
.GroupBy(e => e.SenderId)
.Select(g => new
{
g.Key,
Documents = g.OrderByDescending(e => e.InsertedDateTime).Take(10)
});
但是仍然不支持扁平化(通过 SelectMany
),因此如果您需要这样的查询形状,则必须使用以下解决方法。
原版(EF Core 3.0/3.1/5.0):
这是一个常见问题,不幸的是,EF Core 3.0/3.1/5.0 查询转换器不支持专门针对 GroupBy
。
解决方法是通过关联 2 个子查询来手动进行摸索 - 一个用于键,一个用于相应的数据。
将它应用到您的示例中就像这样。
如果您需要 (key, items) 对:
var query = context.Set<DbDocument>()
.Where(t => partnerIds.Contains(t.SenderId))
.Select(t => t.SenderId).Distinct() // <--
.Select(key => new
{
Key = key,
Documents =
context.Set<DbDocument>().Where(t => t.SenderId == key) // <--
.OrderByDescending(t => t.InsertedDateTime).Take(10)
.ToList() // <--
});
如果您只需要包含每个键前 N 项的简单结果集:
var query = context.Set<DbDocument>()
.Where(t => partnerIds.Contains(t.SenderId))
.Select(t => t.SenderId).Distinct() // <--
.SelectMany(key => context.Set<DbDocument>().Where(t => t.SenderId == key) // <--
.OrderByDescending(t => t.InsertedDateTime).Take(10)
);
我需要在 table 和 entity framework 中获取每个组的前 10 行。 基于 SO 上的其他解决方案,我尝试了两件事:
var sendDocuments = await context.Set<DbDocument>
.Where(t => partnerIds.Contains(t.SenderId))
.GroupBy(t => t.SenderId)
.Select(t => new
{
t.Key,
Documents = t.OrderByDescending(t2 => t2.InsertedDateTime).Take(10)
})
.ToArrayAsync();
错误:
System.InvalidOperationException: 'The LINQ expression
'(GroupByShaperExpression: KeySelector: (d.SenderId),
ElementSelector:(EntityShaperExpression:
EntityType: DbDocument
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False ) )
.OrderByDescending(t2 => t2.InsertedDateTime)' 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().
和
var sendDocuments2 = await context.Set<DbDocument>
.Where(t => partnerIds.Contains(t.SenderId))
.GroupBy(t => t.SenderId)
.SelectMany(t => t.OrderByDescending(t2 => t2.InsertedDateTime).Take(10))
.ToArrayAsync();
错误:
System.InvalidOperationException: 'Processing of the LINQ expression 't => t .OrderByDescending(t2 => t2.InsertedDateTime) .AsQueryable() .Take(10)' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core.
还有其他想法吗?
更新(EF Core 6.0):
EF Core 6.0 增加了对转换 GroupBy
结果集投影的支持,因此获取 (key, items) 的原始代码现在可以正常工作,即
var query = context.Set<DbDocument>()
.Where(e => partnerIds.Contains(e.SenderId))
.GroupBy(e => e.SenderId)
.Select(g => new
{
g.Key,
Documents = g.OrderByDescending(e => e.InsertedDateTime).Take(10)
});
但是仍然不支持扁平化(通过 SelectMany
),因此如果您需要这样的查询形状,则必须使用以下解决方法。
原版(EF Core 3.0/3.1/5.0):
这是一个常见问题,不幸的是,EF Core 3.0/3.1/5.0 查询转换器不支持专门针对 GroupBy
。
解决方法是通过关联 2 个子查询来手动进行摸索 - 一个用于键,一个用于相应的数据。
将它应用到您的示例中就像这样。
如果您需要 (key, items) 对:
var query = context.Set<DbDocument>()
.Where(t => partnerIds.Contains(t.SenderId))
.Select(t => t.SenderId).Distinct() // <--
.Select(key => new
{
Key = key,
Documents =
context.Set<DbDocument>().Where(t => t.SenderId == key) // <--
.OrderByDescending(t => t.InsertedDateTime).Take(10)
.ToList() // <--
});
如果您只需要包含每个键前 N 项的简单结果集:
var query = context.Set<DbDocument>()
.Where(t => partnerIds.Contains(t.SenderId))
.Select(t => t.SenderId).Distinct() // <--
.SelectMany(key => context.Set<DbDocument>().Where(t => t.SenderId == key) // <--
.OrderByDescending(t => t.InsertedDateTime).Take(10)
);