.NET Core 3.0 Entity Frameworkでグループ参加を実行するにはどうすればよいですか?


13

.NET Core 3.0の変更により、

... NavigationExpandingExpressionVisitor 'が失敗しました。これは、EF Coreのバグまたは制限を示している可能性があります。詳細については、https://go.microsoft.com/fwlink/?linkid = 2101433を参照して ください。)---> System.InvalidOperationException:LINQ式 'GroupJoin、...の処理

これは非常に単純なクエリなので、.NET CORE 3.0で実行する方法が必要です。

 var queryResults1 = await patients
            .GroupJoin(
                _context.Studies,
                p => p.Id,
                s => s.Patient.Id,
                (p, studies) => new 
                {
                    p.DateOfBirth,
                    p.Id,
                    p.Name,
                    p.Sex,
                   Studies =studies.Select(s1=>s1)
                }
            )
            .AsNoTracking().ToListAsync();

私は基本的に、Studyを患者に結合するLinqクエリ(または上記のメソッド構文)を探しており、Studyを空のリストに設定するか、特定の患者のスタディがない場合はnullを設定します。

何か案は?これは.NET Core 2.2で機能していました。また、上記のMSFTリンクは、重要な変更がクライアント側の評価に関連しており、生成されたクエリがテーブル全体を読み取ることを回避していることを示しています。ただし、この単純なクエリでは、結合はサーバー側で簡単に実行できるはずです。

回答:


11

ここで説明したように、データベースでサポートされていないクエリを試行しています。EF Core 2はクライアント側の評価を使用してコードを機能させましたが、データセットが増加するとデバッグが困難なパフォーマンスの問題が犠牲になるため、EF Core 3は拒否します。

を使用DefaultIfEmptyして患者のスタディを左結合し、で手動でグループ化できますToLookup

var query =
    from p in db.Patients
    join s in db.Studies on p.Id equals s.PatientId into studies
    from s in studies.DefaultIfEmpty()
    select new { Patient = p, Study = s };

var grouping = query.ToLookup(e => e.Patient); // Grouping done client side

上記の例では、PatientおよびStudyエンティティ全体を取得していますが、代わりに列をチェリーピックすることもできます。患者に必要なデータが大きすぎて各スタディで繰り返すことができない場合は、結合クエリで患者IDのみを選択し、残りの患者データを別の非結合クエリでクエリします。


2
回答が機能します。クエリトランスレータでは、まだやるべきことがいくつかあると思います。このような単純なクエリは翻訳可能である必要があります。FK /インデックスが正しいと想定してデータセットが増加するため、2つのテーブルの単純なグループ結合のパフォーマンスの問題はないはずです。多くの人がこの問題を抱えているのではないかと思います。2テーブルのグループ結合は非常に標準的で、よく使用されるクエリです。
シェルペペレイラ

@ she72同意する。問題は、LINQとSQLが「グループ」キーワードを使用する方法の違いに起因するようです。EF Coreは、LINQ groupbyを左結合に変換する必要があります。これにより、予想より多くの行が戻されなくなります。それに応じてコメントを投稿しました。
エドワードブレイ

私はフォローアップの質問がありますが、このタイプのクエリのグループ化をクライアント側で行う必要がある理由を理解しようとしていますが、新しいLINQフレームワークの制限のようです。上記の場合、クライアント側の実行が予期せず遅くなるリスクはありません。明確にできますか?
shelbypereira

1
さらなるフォローアップとしての主な関心事は、患者ごとに1000の研究がある場合にクライアント側をグループ化する再定式クエリで、各患者をDBから1000回ロードすることですか?この作業をDBで強制的に実行し、グループ化された結果を返す代替手段はありますか?
shelbypereira

1
@ shev72データベースが理解する唯一のグループ化には集計が含まれます。たとえば、患者ごとの研究数を含む患者のクエリの例です。データベースは常に長方形のデータセットを返します。階層的なグループ化は、クライアントによって構成される必要があります。クライアント側の評価としてまたはORMの一部として見ることができます。階層グループ化では、親エンティティデータが繰り返されますが、再クエリは行われません。
Edward Brey

0

まったく同じ問題とそれとの大きな闘争がありました。.net Core 3.0は、メソッド構文で(まだ?)JoinまたはGroupjoinをサポートしていないことがわかります。楽しい部分ですが、クエリ構文で機能します。

これを試してみてください。これは、メソッド構文を少し含むクエリ構文です。これは、適切な左外部結合を持つ正しいSQLクエリに適切に変換され、データベースで処理されます。私はあなたのモデルを持っていないので、自分で構文をチェックする必要があります...

var queryResults1 = 
    (from p in _context.patients
    from s in _context.Studies.Where(st => st.PatientId == p.Id).DefaultIfEmpty()
    select new
    {
        p.DateOfBirth,
        p.Id,
        p.Name,
        p.Sex,
        Studies = studies.Select(s1 => s1)
    }).ToListAsync();

ちなみに、JoinとGroupJoin with Method syntacは、非コアフレームワークとEFで機能します。そして、サーバー側で実行される正しいクエリに変換してください
hwmaat '11

1
Studies in Studies.Select(s1 => s1)
Ankur Arora

モデルは質問に含まれていなかったので、私は研究モデルを知りません。私の推測では、これはモデルの仮想コレクションです。
hwmaat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.