Start Debugging

.NET 11 Preview 5 で LINQ に FullJoin とセレクター不要の join が追加

.NET 11 Preview 5 は LINQ に全く新しい FullJoin 演算子を追加し、さらに Join、LeftJoin、RightJoin、GroupJoin に対して結果セレクターを完全に省けるタプルを返すオーバーロードを追加します。

.NET 11 Preview 5 のライブラリ ノートは、.NET 10 で始まったストーリーを締めくくります。あのリリースは LINQ に LeftJoinRightJoin をもたらし、outer join を GroupJoinSelectManyDefaultIfEmpty で偽装する必要がなくなりました。Preview 5 は欠けていた 4 つ目の角である FullJoin を追加し、ついでにすべての join で最も煩わしい部分、つまり結果セレクターを修正します。

結果セレクターは常に定型コードでした

これまでの join の各オーバーロードは 4 つの引数を取りました。内側のシーケンス、外側のキー、内側のキー、そして一致したペアをどう結合するかを LINQ に伝える結果セレクターです。10 回のうち 9 回、そのセレクターは 2 つの項目を匿名型かタプルに貼り合わせるだけでした。

var pairs = catalog.Join(
    sales,
    p => p.Sku,
    s => s.Sku,
    (product, sale) => (product, sale));

foreach (var (product, sale) in pairs)
    Console.WriteLine($"{product.Name}: sold {sale.Quantity}");

この最後のラムダはロジックを一切持ちません。シグネチャを満たすためだけに存在します。Preview 5 は JoinLeftJoinRightJoinGroupJoin に対して、明白な形を推論してそれを省略できる、タプルを返すオーバーロードを追加します。

foreach (var (product, sale) in catalog.Join(sales, p => p.Sku, s => s.Sku))
    Console.WriteLine($"{product.Name}: sold {sale.Quantity}");

Join は今や IEnumerable<(TOuter, TInner)> を返します。GroupJoinIEnumerable<(TOuter, IEnumerable<TInner>)> を返します。左と右のバリアントは、SQL がそうするのとまったく同じように、外側または内側を null 許容として返します。これらのオーバーロードは EnumerableQueryableAsyncEnumerable に存在するため、同じ呼び出しの形がインメモリのコレクション、EF Core のクエリツリー、非同期ストリームで機能します。

FullJoin がセットを完成させる

本当に新しい演算子が FullJoin (dotnet/runtime #127236) です。full outer join は両方のシーケンスからすべての要素を返し、キーが一致するものをペアにし、一致しないものには null の相手を残します。2 つのリストの突き合わせ、たとえば製品カタログと販売フィードの照合は、これまで 2 回のパスか手作りのディクショナリ検索を意味しました。今では 1 回の呼び出しです。

foreach (var (product, sale) in catalog.FullJoin(sales, p => p.Sku, s => s.Sku))
{
    if (product is null)
        Console.WriteLine($"Sale for unknown SKU {sale!.Sku}");
    else if (sale is null)
        Console.WriteLine($"No sales for {product.Name}");
    else
        Console.WriteLine($"{product.Name}: sold {sale.Quantity}");
}

ここではどちらの側も欠けうるため、タプルの両側が null 許容です。そして C# の null 許容型の注釈が、両方のギャップを処理するようコンパイラーがあなたを促します。

これに頼る前に知っておくべきこと

これらは LINQ のメソッド構文への追加のみです。full join というクエリのキーワードはなく、既存のクエリ式の形は手つかずのままです。EF Core のプロバイダーでは、FullJoinFULL OUTER JOIN に変換されるか、クライアント評価にフォールバックするかは、プロバイダーが追いつくかどうかに依存します。そのため、データベースで実行されると仮定する前に、生成された SQL を確認してください。Preview 5 の他の部分と同様に、新しい System.Text.Json の JSON Lines サポートを含め、シグネチャは 11 月の安定版リリースまでにまだ変わる可能性があります。しかし形は十分にきれいなので、今日から結果セレクターのラムダを削除し始められます。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る