New in .NET 10.0 [23]: New LINQ operators LeftJoin() and RightJoin()
A Left (Outer) Join and a Right (Outer) Join were already possible in LINQ. In .NET 10.0, there are now dedicated operators for this.
(Image: Pincasso / Shutterstock.com)
- Dr. Holger Schwichtenberg
As with the last .NET versions, Microsoft is again releasing new operators for Language Integrated Query (LINQ) in .NET 10.0 that simplify existing constructs. This time, with LeftJoin() and RightJoin(), there are two elementary operators, one from set theory and the other for relational databases. More on this can be found in the associated issue on GitHub.
In fact, these operations were already possible in LINQ before, but only in a cumbersome way via grouping with GroupJoin() and SelectMany() as well as DefaultIfEmpty(). The new methods LeftJoin() and RightJoin() simplify their use, as the following code shows using the example of a join between the Company and Website classes:
public void LeftRightJoin()
{
CUI.Demo();
Company[] companies =
[
new Company{ ID = 1, Name = "www.IT-Visions.de" },
new Company{ ID = 2, Name = "Software & Support" },
new Company{ ID = 3, Name = "Heise Gruppe GmbH & Co. KG" },
new Company{ ID = 4, Name = "Startup i.Gr." } // hat noch keine Website
];
Website[] websites =
[
new Website{ CompanyID = 1, URL = "www.IT-Visions.de" },
new Website{ CompanyID = 1, URL = "www.dotnet10.de" },
new Website{ CompanyID = 2, URL = "www.entwickler.de" },
new Website{ URL = "www.Microsoft.com" }, // Diese kleine ;-) Firma ist noch nicht angelegt...
new Website{ CompanyID = 3, URL = "www.heise.de" },
];
// ### LeftJOIN ALT ############################################################################
CUI.H2("--- Alle Firmen mit ggf. vorhandenen Websites via LeftJoin ALT (GroupJoin+SelectMany) seit .NET Framework 3.5 ---");
var AllCompaniesWithWebsitesSetOld = companies
.GroupJoin(websites,
c => c.ID,
w => w.CompanyID,
(c, websites) => new { Company = c, Websites = websites })
.SelectMany(
x => x.Websites.DefaultIfEmpty(), // Falls keine Website existiert, wird `null` verwendet
(c, w) => new WebsiteWithCompany
{
Name = c.Company.Name,
URL = w.URL, // Falls `w` null ist, bleibt URL null
City = c.Company.City
});
foreach (var item in AllCompaniesWithWebsitesSetOld)
{
Console.WriteLine((item.Name != null ? item.Name + " " + item.City : "- keine Firma -").Trim() + " -> " + (item.URL ?? "- keine URL -"));
}
// ### LeftJOIN NEU ############################################################################
CUI.H2("--- Alle Firmen mit ggf. vorhandenen Websites via LeftJoin NEU ab .NET 10.0 ---");
var AllCompaniesWithWebsitesSet = companies.LeftJoin(websites,
e => e.ID,
e => e.CompanyID,
(c, w) => new WebsiteWithCompany { Name = c.Name, City = c.City, URL = w.URL }
);
foreach (var item in AllCompaniesWithWebsitesSet)
{
Console.WriteLine((item.Name != null ? item.Name + " " + item.City : "- keine Firma -").Trim() + " -> " + (item.URL ?? "- keine URL -"));
}
// ### RightJoin ALT ############################################################################
CUI.H2("--- Alle Websites mit ggf. vorhandenen Firmen via RightJoin ALT (GroupJoin+SelectMany) seit .NET Framework 3.5 ---");
var WebsiteWithCompanySetOLD = websites
.GroupJoin(companies,
w => w.CompanyID,
c => c.ID,
(w, companies) => new { Website = w, Companies = companies })
.SelectMany(
x => x.Companies.DefaultIfEmpty(), // Falls kein Unternehmen existiert -> null
(w, c) => new WebsiteWithCompany
{
Name = c.Name, // Falls `c` null ist, bleibt `Name` null
City = c.City, // Falls `c` null ist, bleibt `City` null
URL = w.Website.URL
});
foreach (var item in WebsiteWithCompanySetOLD)
{
Console.WriteLine((item.Name != null ? item.Name + " " + item.City : "- keine Firma -").Trim() + " -> " + (item.URL ?? "- keine URL -"));
}
// ### RightJoin NEU ############################################################################
CUI.H2("--- Alle Websites mit ggf. vorhandenen Firmen via RightJoin NEU ab .NET 10.0 ---");
var WebsiteWithCompanySet = companies.RightJoin(websites,
e => e.ID,
e => e.CompanyID,
(c, w) => new WebsiteWithCompany { Name = c.Name, City = c.City, URL = w.URL }
);
foreach (var item in WebsiteWithCompanySet)
{
Console.WriteLine((item.Name != null ? item.Name + " " + item.City : "- keine Firma -").Trim() + " -> " + (item.URL ?? "- keine URL -"));
}
// ### Zum Vergleich: Inner Join, den es seit .NET Framework 3.5 gibt
CUI.H2("--- Alle Firmen, die Websites haben, via InnerJoin seit .NET Framework 3.5 ---");
var CompaniesWithWebsitesSet = companies.Join(websites,
c => c.ID,
w => w.CompanyID,
(c, w) => new WebsiteWithCompany
{
Name = c.Name,
URL = w.URL,
City = c.City
});
foreach (var item in CompaniesWithWebsitesSet)
{
Console.WriteLine((item.Name != null ? item.Name + " " + item.City : "- keine Firma -").Trim() + " -> " + (item.URL ?? "- keine URL -"));
}
}
Videos by heise
According to Microsoft, the new operators are more performant than the previous operator combination.
(Image:Â Microsoft)
(mho)