Entity Framework and forced Inner Join

EF seems to use INNER JOIN for including a required and LEFT OUTER JOIN for including an optional navigation property. Example:

public class Order
{
    public int Id { get; set; }
    public string Details { get; set; }
    public Customer Customer { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

If I define Customer as a required property on Order

public class MyContext : DbContext
{
    public DbSet<Order> Orders { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .HasRequired(o => o.Customer)
            .WithMany();
    }
}

…and issue this query…

using (var ctx = new MyContext())
{
    var result = ctx.Orders
        .Include(o => o.Customer)
        .Where(o => o.Details == "Peanuts")
        .FirstOrDefault();
}

…I get this SQL:

SELECT TOP (1) 
[Extent1].[Id] AS [Id], 
[Extent1].[Details] AS [Details], 
[Extent2].[Id] AS [Id1], 
[Extent2].[Name] AS [Name]
FROM  [dbo].[Orders] AS [Extent1]
INNER JOIN [dbo].[Customers] AS [Extent2] 
    ON [Extent1].[Customer_Id] = [Extent2].[Id]
WHERE N'Peanuts' = [Extent1].[Details]

If I change in the model configuration .HasRequired(o => o.Customer) to…

.HasOptional(o => o.Customer)

… I get exactly the same query except that INNER JOIN [dbo].[Customers] AS [Extent2] is replaced by:

LEFT OUTER JOIN [dbo].[Customers] AS [Extent2]

From model viewpoint it makes sense because you are saying that there can never be an Order without a Customer if you define the relationship as required. If you circumvent this requirement by removing the enforcement in the database and if you actually have then orders without a customer you violate your own model definition.

Only solution is likely to make the relationship optional if you have that situation. I don’t think it is possible to control the SQL that is created when you use Include.

Leave a Comment