如何使用EF 3.1为Entity Framework GroupBy中的每个组选择前N行

时间:2019-12-23 13:16:31

标签: entity-framework group-by entity-framework-core ef-core-3.1

我需要使用实体框架为表中的每个组获取前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:'处理LINQ表达式   't => t       .OrderByDescending(t2 => t2.InsertedDateTime)       .AsQueryable()       .NavigationExpandingExpressionVisitor的“ .Take(10)”失败。这可能表示EF Core中存在错误或限制。

还有其他想法吗?

2 个答案:

答案 0 :(得分:1)

这是一个常见问题,遗憾的是,专门针对GroupBy的EF Core 3.0 / 3.1查询转换器不支持。

解决方法是通过关联2个子查询来手动进行摸索-一个用于键,另一个用于对应的数据。

将其应用于示例将是这样。

如果您需要(键,项)对:

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)
    );

答案 1 :(得分:0)

也许尝试其他方法?

 var partnersList = context.partnerIds.Where(x=> "your where clause here").Take(10).Tolist()
相关问题