HomeNikola Knezevic

In this article

Banner

LeftJoin and RightJoin Operators in EF Core

13 Nov 2025
5 min

Special Thanks to Our Sponsors:

Sponsor Logo

EF Core is too slow? Discover how you can easily insert 14x faster (reducing saving time by 94%).

Boost your performance with our method within EF Core: Bulk Insert, update, delete and merge.

Thousands of satisfied customers have trusted our library since 2014.

👉 Learn more

Sponsor Newsletter

Joins are one of the most fundamental concepts when working with SQL.

They allow you to combine related data from multiple tables based on shared relationships.

Joins are everywhere, you’ll find them in almost every application that deals with relational data.

For example, fetching blog posts with comments, products with reviews or customers with their orders.

However, until now, performing something as common as a Left Join in LINQ required a combination of GroupJoin, SelectMany and DefaultIfEmpty.

While it worked, the syntax was verbose and far from elegant.

With .NET 10, EF Core introduces native LeftJoin and RightJoin operators, dramatically simplifying what used to be a verbose LINQ pattern.

Getting Started

To follow along, we need a new .NET 10 project with simple entities:

csharp
public class Order
{
    public Guid Id { get; set; }
    public List<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public Guid OrderId { get; set; }
}

Order and OrderItem model will represent a one-to-many relationship.

Left Join

Left Join returns all records from the left table (Orders) and matches them with related records from the right table (OrderItems).

If an order has no items, it still appears in the result with NULL values for the right-side columns.

Here's an example in SQL:

sql
SELECT
    o."Id" AS order_id,
    oi."Id" AS item_id,
    oi."Name" AS item_name,
    oi."Price" AS item_price
FROM
    "Orders" o
LEFT JOIN
    "OrderItems" oi
ON
    o."Id" = oi."OrderId";

Before .NET 10, this is how you had to get the same behavior with LINQ queries:

csharp
var query =
    from o in dbContext.Orders
    join oi in dbContext.OrderItems
    on o.Id equals oi.OrderId into orderItemsGroup
    from oi in orderItemsGroup.DefaultIfEmpty()
    select new
    {
        order_id = o.Id,
        item_id = oi != null ? oi.Id : (Guid?)null,
        item_name = oi != null ? oi.Name,
        item_price = oi != null ? oi.Price : (decimal?)null
    };

Honestly, here's a rare example where I favored linq queries compared to linq methods:

csharp
var query =
    dbContext.Orders
        .GroupJoin(
            dbContext.OrderItems, 
            o => o.Id, 
            i => i.OrderId, 
            (o, items) => new { o, items })
        .SelectMany(
            x => x.items.DefaultIfEmpty(), 
            (x, item) => new
            {
                OrderId = x.o.Id,
                ItemId = item.Id != null ? item.Id : (Guid?)null,
                ItemName = item.Name,
                ItemPrice = item.Price != null ? item.Price : (decimal?)null
            });

With EF Core 10, you can now express this with a single, intuitive call:

csharp
var result = await dbContext.Orders.LeftJoin(
    dbContext.OrderItems,
    order => order.Id,
    item => item.OrderId,
    (order, item) => new
    {
        order.Id,
        ItemName = item.Name,
        ItemPrice = item.Price != null ? item.Price : (decimal?)null
    }).ToListAsync();

No GroupJoin, no DefaultIfEmpty, just one simple LeftJoin method.

To perform left join we need to specify a key from the left table that we want to join on and a key from the right table that we want to join on.

Lastly we used projection to shape what the result should look like.

Because the method is implemented by using deferred execution, we need to use ToList in order to materialize the result.

Right Join

Right Join does the opposite, it returns all records from the right table and matches them with those from the left.

Here's an example in SQL:

sql
SELECT
    o."Id" AS order_id,
    oi."Id" AS item_id,
    oi."Name" AS item_name,
    oi."Price" AS item_price
FROM
    "OrderItems" oi
RIGHT JOIN
    "Orders" o
ON
    o."Id" = oi."OrderId";

Now, EF Core 10 lets you do this natively too:

csharp
var result = await dbContext.OrderItems.RightJoin(
    dbContext.Orders,
    item => item.OrderId,
    order => order.Id,
    (item, order) => new
    {
        order.Id,
        ItemName = item.Name,
        ItemPrice = item.Price != null ? item.Price : (decimal?)null
    }).ToListAsync();

Conclusion

EF Core 10’s introduction of native LeftJoin and RightJoin operators marks a significant simplification how we write join statements.

What once was verbose LINQ can now be expressed in a single, intuitive method call.

If you want to check out examples I created, you can find the source code here:

Source Code

I hope you enjoyed it, subscribe and get a notification when a new blog is up!

Subscribe

Stay tuned for valuable insights every Thursday morning.