Return parents with null children using C# EF Core .Include

c# entity-framework entity-framework-core

Question

Our goal is to query a database, using Entity Framework Core and the .Include(...) extension method to return a collection of objects that have a child, where some of the children will be null.

We have a table Projects with a C# model Project and a table Locations with a C# model Location.

Each Project has a one or zero Location objects and the objects look like this:

public class Project
{
     public string LocationId { get; set; }
     public Location Location { get; set; }
}

public class Location
{
     public string LocationId { get; set; }
}

Database setup looks like this:

        modelBuilder.Entity<Location>(entity =>
        {
            entity.HasKey(location => location.LocationId);
            entity.ToTable("Locations");
        });
        modelBuilder.Entity<Project>(entity =>
        {                
            entity.HasOne(project => project.Location).WithMany()
            .HasForeignKey(x => x.LocationId);                
            entity.ToTable("Projects");

        });

The query we've created is:

var projects = dbContext.Projects.Include(x => x.Location);

The SQL that EF generates includes a LEFT JOIN when we'd expect a LEFT OUTER JOIN:

SELECT [project].[LocationId] 
FROM [Projects] AS [project] 
LEFT JOIN [Locations] AS [c] ON [project].[LocationId] = [c].[LocationId]

The result is that only Projects with Locations are returned. We want all Projects and their Locations.

From this link I understand that .Include(...) determines to do a LEFT JOIN or a LEFT OUTER JOIN depending on the nullability of the foreign key:

Code First infers the multiplicity of the relationship based on the nullability of the foreign key. If the property is nullable then the relationship is registered as optional.

As that isn't what happens, there is something missing.

What modifications need to be made to return all Projects, regardless of if their Location will be populated?

Thanks!

1
2
1/19/2018 7:47:01 PM

Popular Answer

I hit this situation, except the generated SQL is:

INNER JOIN [Blah.[Table] AS [x.Child] ON [x].[ChildId] = [x.Child].[Id]

This genuinely causes the problem, whereas the question's LEFT JOIN would be fine (as others have pointed out).

So why was this happening? My ChildId is a Guid, and I had made sure to make it a Guid? as nullability makes it optional.

I next tried adding .IsRequired(false) to the mapping for ChildId. This gave an error that told me what the actual problem was: I had also included ChildId (unnecessarily) in the primary key.

Removing it from the primary key caused the query to change to a LEFT JOIN and all is good.

2
4/19/2018 10:20:16 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow