web-dev-qa-db-ja.com

EF Core 2からEF Core 3への移行

プロジェクトを(dotnet core 2/ef core 2)から(dotnet core 3/ef core 3)にアップグレードすると、エンティティフレームワークのLINQクエリのほとんどすべてが壊れます。私はすでに読んでいますが this 何をすべきかを知ることはまだ不明です。

ここに私が問題を抱えているいくつかの例があります:

var league = await dbContext.League.LastAsync();

このコードはef core 2では問題なく機能しましたが、ef core 3では例外をスローします。これについて見つけることができる唯一の回避策は、以前のように非同期ではないため、私が望んでいない次のコードだけです。

var league = dbContext.League.AsEnumerable().Last();

同じ例外をスローする別の例は、次のコードです。

var user = await dbContext.User.FirstOrDefaultAsync(u =>
                u.UserId == userId && string.Equals(u.Token, token, StringComparison.InvariantCulture));

AsEnumerable()は引き続き使用できますが、FirstOrDefaultの非同期バージョンは利用できないため、これはオプションではありません。誰かがこれで私を案内できますか?

[〜#〜]編集[〜#〜]
これは例外です:

System.InvalidOperationException: The LINQ expression 'Last<League>(DbSet<League>)' 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.
9
Shahriyar

EF Core 3.0で発生したいくつかの異なる変更に対応しているため、質問への回答は非常に冗長になります。それでは、そのほんの一部を考えてみましょう。

あなたの質問で述べたように、Microsoftは この投稿 のバージョン3.0での変更について、ややわかりにくい説明をしています。

上記の投稿の最初の部分は次のとおりです: 'LINQクエリはクライアントで評価されなくなりました'。それは、開発者が2つの部分を含むクエリを作成するために使用する前に述べています。 1つはデータベースに対するクエリで、もう1つはクライアントコードでしか認識されない式でした。この状況では、_client evaluation of potentially expensive expressions only triggered a warning_です。ただし、新しいバージョンでは、EFコアはクライアントでの最後のSelect()呼び出しの評価のみを許可し、SQLまたはパラメーターに変換できない式がある場合は例外をスローします。

この部分を明確にするために、Diego Vegaが EF Core 3.0発表のブログ投稿 で説明した例を見てみましょう。

クライアント評価に明示的に切り替える:クエリがSQLに変換できない式に基づいてデータをフィルタリングする場合、AsEnumerable()、AsAsyncEnumerable()のいずれかに呼び出しを挿入して、クライアント評価に明示的に切り替える必要がある場合があります。 )、ToList()、またはToListAsync()をクエリの途中で使用します。たとえば、次のクエリはEF Core 3.0では機能しなくなります。これは、where句の述語の1つがクライアントの評価を必要とするためです。

_var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));
_

ただし、クライアントでフィルターの一部を処理することが妥当であることがわかっている場合は、クエリを次のように書き換えることができます。

_var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n)) 
    .AsEnumerable() // Start using LINQ to Objects (switch to client evaluation)
    .Where(c => IsSpecialCustomer(c));
_

上記の例では、IsSpecialCustomer(c)は、クライアントコードでのみ使用可能なC#メソッドであるため、SQLに変換できないメソッドです。そのため、開発者は翻訳可能な形式でクエリを書き直すか、データベースでクエリを実行してから、.AsEnumerable()を使用してデータベースの結果をクライアントに評価し、IsSpecialCustomer(c)に基づいて結果をフィルタリングすることができます。戻り値。 このため、コード内でAsEnumerable()に引き続きアクセスできます。

では、FirstOrDefaultAsync()メソッドが使用できない理由を見てみましょう。

まあ、この状況を引き起こす2つの理由があります。

以前に最初の理由に答えたことがあります。バージョン3.0では、構成不可能なSQLを検出するコードが削除されました。

そして2つ目は、クエリパイプラインが式ツリー内の非同期のクエリ可能な演算子を理解しない場合です(例:EF.CompileQuery()でアクセスしようとしている場合)。

全体として、あなたが読むことができるいくつかの興味深い投稿があります:

40 ef core 3の悪い変更を壊す

エンティティフレームワークコア3.0プレビュー9およびエンティティフレームワーク6.3プレビュー9の発表

githubのEFコアの問題

8
user6311045
  1. 一部のプロパティにはOrderByDesc()を使用し、次にFirstAsync()を使用します。 ( https://github.com/aspnet/EntityFrameworkCore/issues/18211

  2. 不変比較は翻訳されていません。おそらく以前にクライアントが評価したものです。データベースの照合設定に応じて、ここで通常の等号を実行できます。

フィルターなしでDbSetAsEnumerable()を呼び出すと、すべてのデータがローカルでプルダウンされます。本番環境で実行したいものではありません。上記に書き直して、生成されたSQLを監視し、パフォーマンスの高いクエリが確実に得られるようにしてください。

3
jcemoller