LINQ Full Outer Join in .NET 11

LINQ Full Outer Join in .NET 11

- Matt

Zwei Listen, die sich nur in der Mitte überschneiden: Kunden mit Bestellungen, Bestellungen ohne Kunden, Kunden ohne Bestellung. Ich will alle drei Gruppen in einem Durchgang. In SQL ist das ein FULL OUTER JOIN, in LINQ gab es dafür lange nichts Eingebautes, nur die Krücke aus GroupJoin und DefaultIfEmpty.

Mit .NET 10 kamen LeftJoin und RightJoin dazu. Ein FullJoin fehlt aber immer noch. Für .NET 11 ist eins vorgeschlagen und im API-Review durchgewunken, mit Func<TOuter?, TInner?, TResult>, weil hier beide Seiten fehlen können. Nur liegt dazu kein PR in der Runtime, das Ding ist bislang Papier. Wer heute einen Full Outer Join braucht, setzt ihn aus LeftJoin plus den Zeilen zusammen, die nur rechts stehen:

var links = kunden.LeftJoin(bestellungen,
    k => k.Id, b => b.KundeId, (k, b) => (k, b));

var nurRechts = bestellungen
    .Where(b => kunden.All(k => k.Id != b.KundeId))
    .Select(b => ((Kunde?)null, b));

var full = links.Concat(nurRechts);

Der Haken steckt im Where: es scannt für jede rechte Zeile die linke Seite komplett, also O(n*m). Bei zwei großen Listen vorher ein HashSet der linken Schlüssel bauen und darin nachsehen. Für den Alltag mit ein paar hundert Einträgen reicht die einfache Variante, aber verlassen würde ich mich nicht darauf, dass das FullJoin es wirklich in .NET 11 schafft.