web-dev-qa-db-ja.com

EF 3.1でEntity Framework GroupByの各グループの上位N行を選択する方法

エンティティフレームワークを使用して、テーブルの各グループの上位10行を取得する必要があります。 SOの他のソリューションに基づいて、私は2つのことを試しました:

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().Take(10) 'による' NavigationExpandingExpressionVisitor 'による処理が失敗しました。これは、EF Coreのバグまたは制限を示している可能性があります。

他のアイデアは?

5
Makla

これは一般的な問題であり、残念ながら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)
    );
3
Ivan Stoev

多分別のアプローチを試してみませんか?

 var partnersList = context.partnerIds.Where(x=> "your where clause here").Take(10).Tolist()
0
Asım Gündüz