← Back to blog
20 March 20263 min read

EF Core 10 Just Got Cleaner LeftJoin & RightJoin in LINQ

EF Core 10 introduces first-class LeftJoin and RightJoin operators, making LINQ queries cleaner, more readable, and easier to maintain.

.NET.NETEF CoreLINQBackend

If you've worked with relational databases long enough, you already know how essential LEFT JOIN and RIGHT JOIN are.

But if you've used Entity Framework Core before .NET 10… you also know the pain πŸ˜…

Writing a simple left join in LINQ used to feel unnecessarily complicated β€” involving GroupJoin, DefaultIfEmpty, and SelectMany. It worked, but the intent was far from obvious.

Good news: EF Core 10 finally introduces LeftJoin and RightJoin β€” making your code much closer to how you think.


πŸ€” What is a LEFT JOIN (simple explanation)?

A LEFT JOIN returns:

  • All records from the left side
  • Matching records from the right side
  • If no match β†’ right side = null

πŸ“Œ Example scenario

Imagine you have:

  • Customers
  • Orders

πŸ‘‰ You want to show all customers, even those who haven't placed any orders yet.


πŸ˜“ The Old Way (Before .NET 10)

To perform a left join, you had to write something like this:

Query syntax

var query =
    from customer in dbContext.Customers
    join order in dbContext.Orders
        on customer.Id equals order.CustomerId into orderGroup
    from subOrder in orderGroup.DefaultIfEmpty()
    select new
    {
        CustomerId = customer.Id,
        customer.Name,
        OrderId = (int?)subOrder.Id ?? 0,
        Total = (decimal?)subOrder.Total ?? 0
    };

Method syntax

var query = dbContext.Customers
    .GroupJoin(
        dbContext.Orders,
        customer => customer.Id,
        order => order.CustomerId,
        (customer, orders) => new { customer, orders })
    .SelectMany(
        x => x.orders.DefaultIfEmpty(),
        (x, order) => new
        {
            CustomerId = x.customer.Id,
            x.customer.Name,
            OrderId = (int?)order!.Id ?? 0,
            Total = (decimal?)order!.Total ?? 0
        });

😡 Why this is painful:

  • Too verbose for such a common operation
  • Hard to read (intent is hidden)
  • Easy to get wrong
  • Not beginner-friendly

πŸš€ The New Way: LeftJoin (EF Core 10)

Now we can finally write what we mean:

var query = dbContext.Customers
    .LeftJoin(
        dbContext.Orders,
        customer => customer.Id,
        order => order.CustomerId,
        (customer, order) => new
        {
            CustomerId = customer.Id,
            customer.Name,
            OrderId = (int?)order.Id ?? 0,
            Total = (decimal?)order.Total ?? 0
        });

πŸ’₯ Why this is a big deal

  • βœ… Much cleaner & shorter
  • βœ… Intent is obvious immediately
  • βœ… No more GroupJoin + DefaultIfEmpty
  • βœ… Same SQL generated under the hood

πŸ”„ What about RIGHT JOIN?

EF Core 10 also introduces RightJoin.

πŸ‘‰ It does the opposite:

  • Keeps all records from the right side
  • Matches from the left (if available)

πŸ“Œ Example

Say you want:

πŸ‘‰ Show all orders, even if some customers were deleted or missing

var query = dbContext.Customers
    .RightJoin(
        dbContext.Orders,
        customer => customer.Id,
        order => order.CustomerId,
        (customer, order) => new
        {
            CustomerName = customer.Name,
            OrderId = order.Id,
            order.Total
        });

⚠️ Important Notes

  • Currently, query syntax (from ... select) does NOT support LeftJoin/RightJoin
  • You must use method syntax

βΈ»

🧠 When will you use this?

Honestly… everywhere:

  • Customers with optional orders
  • Users with optional profiles
  • Products with optional discounts
  • Employees with optional departments

Before, people sometimes:

  • Wrote multiple queries ❌
  • Used INNER JOIN accidentally (losing data) ❌

Now β†’ no excuse 😎

βΈ»

πŸ› οΈ Best Practices

  • Always handle nulls on the optional side
order.Total ?? 0
  • Keep your projections lean (avoid selecting unnecessary columns)
  • Add indexes on join keys for performance

βΈ»

🧾 Final Thoughts

This is one of those small features that makes a huge difference in daily coding.

With LeftJoin and RightJoin:

  • Code is cleaner
  • Intent is clearer
  • Bugs are less likely

πŸ‘‰ Finally, LINQ feels closer to SQL β€” without the pain.

Support My Work

If you've enjoyed my content and found it helpful, consider buying me a coffee. It keeps me caffeinated and creating!

Buy me a coffee