Maru@maru

Dev Hub

Translated from Korean

EF Core 10 クエリ変換はどう変わったか:LeftJoinのサポートとコレクションパラメータの刷新

リレーショナルデータベースとオブジェクトモデルをつなぐORMにおいて、クエリ変換はパフォーマンスとコードの可読性を左右する重要な領域です。 .NET 10とともに登場したEF Core 10は、長年開発者を悩ませてきた複雑なLINQの記述パターンを整理し、実際のデータベース実行計画を最適化するように基本的な変換方式を改善しました。

最も注目すべき変化は、外部結合構文の簡素化とコレクションパラメータ変換戦略の変更です。これに加え、SQL Server 2025のベクトル検索サポートや一括更新メソッドの柔軟性向上も実現しました。何がどう変わり、実務プロジェクトで何を確認すべきか、順を追って見ていきます。

20年越しに解消されたGroupJoinの回避策とLeftJoinの導入

従来のLINQでは、2つのテーブル間で一致しないデータまで含めて取得する外部結合の表現が非常に困難でした。SQLであればLEFT JOINの一行で済む作業が、C#コードではGroupJoin、SelectMany、DefaultIfEmptyという3つのメソッドを特定の順序で組み合わせる必要がありました。コードが長くなるだけでなく、意図を直感的に把握するのも困難でした。

.NET 10 LINQとEF Core 10は、ネイティブなLeftJoinおよびRightJoin演算子を標準APIとしてサポートしています。これまでのような複雑なメソッドチェーンを使わなくても、メソッドを呼び出すだけでスッキリと外部結合を宣言できます。

EF Core 10環境で記述するLeftJoinの例です。

csharp

変換の結果生成されるSQLは、従来の複雑な回避策と同様に、すっきりとしたLEFT JOIN構文に翻訳されます。パフォーマンス上のメリット以上に、コードの可読性と保守性を劇的に向上させる変更です。

コレクションパラメータのデフォルト翻訳方式の切り替え

リストに含まれる項目でフィルタリングを行う際に使用するContainsクエリは、データベースエンジン側から見ると実行計画を立てるのが難しい対象でした。以前のバージョンでは、パラメータ化されたコレクションを単一のJSON配列として渡すか、データベース固有の関数で処理する手法が多く使われていました。しかし、これではオプティマイザが実際の件数を予測できず、非効率な実行計画を選択してしまう原因になることもありました。

EF Core 10では、パラメータコレクションの翻訳モードのデフォルトが、マルチスカラーパラメータ方式に変更されました。これからはWhere(b => ids.Contains(b.Id))のようなクエリは、複数のSQLクエリパラメータに分割して渡されます。これにより、データベースオプティマイザが正確なカーディナリティ(濃度)推定を行えるようになるため、大規模データ検索時も安定したパフォーマンスが期待できます。従来のJSONベースの変換や定数埋め込みが必要な特殊なケースについては、グローバルオプションやクエリごとのメソッドを通じて、以前の動作方式を指定することも可能です。

一括更新の柔軟性と最新機能の拡張

データベースのレコードをメモリに読み込むことなく直接更新するExecuteUpdateAsyncAPIにも実用的な改善が反映されました。これまで式ツリー(Expression Tree)のみが許可されていたため、条件付きプロパティ修正や動的な更新クエリを記述する際には、式を手作業で組み立てる必要があり不便でした。今回のバージョンでは、通常のActionラムダを引数として渡せるよう拡張され、動的な修正ロジックがより柔軟に記述できるようになりました。

AIアプリケーション開発の潮流に合わせ、SQL Server 2025およびAzure SQLのベクトル検索機能も正式サポートリストに加わりました。LINQ内でベクトル距離計算関数や専用型を使用し、意味に基づいた類似度検索を標準クエリのように呼び出すことができます。

導入時の注意点

EF Core 10は.NET 10のランタイムとSDKが必須です。下位ランタイムのプロジェクトではパッケージを直接アップグレードできないため、ランタイム全体のアップグレードスケジュールを合わせて調整する必要があります。マルチターゲットプロジェクトでマイグレーションツールを実行する際は、対象フレームワークのフラグを明示する必要があるといった変更点もあります。

コレクションパラメータのデフォルト値がマルチスカラー方式に変わったことで、数千件以上のキーリストをContainsに渡すと、パラメータ数の制限に達したり、クエリキャッシュエントリが急増したりする可能性があります。プロジェクトのデータの特性に合わせて、デフォルトモードを維持するか、大量検索を行う領域に限定して代替設定を適用するかを検討することをお勧めします。

Loading comments…