EF Core 10 Makes Outer Joins Beautiful Again
Left & Right Joins now feel as natural as SQL.
Entity Framework Core has come a long way, but one thing that always felt awkward was performing outer joins. While SQL offers clean LEFT and RIGHT join syntax, LINQ forced developers into more verbose patterns especially when retrieving all records from one table regardless of match.
With EF Core 10, that finally changes.
Why Outer Joins Matter
In real projects, we often need to fetch all entities from one table, including those with no related data. For example:
A campaign may exist even if no assets were uploaded yet
A file could be imported before a campaign is attached to it
Reports often need complete datasets, even with missing associations
Until now, LINQ made this harder than necessary.
EF Core 10 changes that elegantly.
Example Scenario
Let’s imagine a common marketing structure:
Campaign → a promotional or marketing effort
CampaignAsset → images, files, or collateral linked to the campaign
Entity Definitions
public class Campaign
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
public class CampaignAsset
{
public int Id { get; set; }
public int CampaignId { get; set; }
public string FileName { get; set; } = string.Empty;
}Our goal: retrieve all campaigns — even those without assets.
EF Core 10: Left Join (Left Outer Join)
EF Core 10 introduces a clean new operator: .LeftJoin(), making this operation finally feel natural.
var query = context.Campaigns
.LeftJoin(
context.CampaignAssets,
campaign => campaign.Id,
asset => asset.CampaignId,
(campaign, asset) => new
{
Campaign = campaign,
Asset = asset
});This is LINQ the way it was meant to be.
SQL Generated
SELECT *
FROM Campaigns AS c
LEFT JOIN CampaignAssets AS a
ON c.Id = a.CampaignId;EF Core 10: Right Join (Right Outer Join)
Less common, but extremely useful when reconciling external data sources or validating imported files.
var query = context.Campaigns
.RightJoin(
context.CampaignAssets,
campaign => campaign.Id,
asset => asset.CampaignId,
(campaign, asset) => new
{
Campaign = campaign,
Asset = asset
});Right joins now require no workaround — finally.
Before vs After EF Core 10
❌ Old Approach — Functional, but clunky
var query =
from c in context.Campaigns
join a in context.CampaignAssets
on c.Id equals a.CampaignId into assets
from a in assets.DefaultIfEmpty()
select new { c, a };It works — but the intent is buried in syntax.
✅ New EF Core 10 Approach — Elegant & expressive
var query = context.Campaigns
.LeftJoin(
context.CampaignAssets,
c => c.Id,
a => a.CampaignId,
(c, a) => new { c, a });Readable. Direct. Maintainable.
This is what modern LINQ should look like.
Final Thoughts
EF Core 10 didn’t just add an operator — it improved the developer experience.
Outer joins are finally straightforward in LINQ, making queries easier to read, write, and teach.
If you’re using EF Core professionally, this is an upgrade worth adopting.
Clean code scales — and this feature is a perfect example.
👉 Full working code available at:
🔗https://sourcecode.kanaiyakatarmal.com/EFCore10OuterJoins
I hope you found this guide helpful and informative.
Thanks for reading!
If you enjoyed this article, feel free to share it and follow me for more practical, developer-friendly content like this.


