Extra join in query for value objects in Entity Framework Core

.net-core asp.net-core entity-framework-core value-objects


In Entity Framework Core 3.1.3, I have used the value object feature. In the query side, the problem is an extra left join exists in T-SQL. This extra join results in problems in terms of performance. In the following code Student is an Entity type and Address class is a value type.


public class Student
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }

public class Address
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }


public class ApplicationDbContext : DbContext
    public DbSet<Student> Students { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
        builder.Entity<Student>().OwnsOne(e => e.Address);

Entity Framework query

var list = _dbContext.Students.ToList();

Generated T-SQL for this EF query:

SELECT [s].[Id], [s].[Name], [t].[Id], [t].[Address_City], 
       [t].[Address_Street], [t].[Address_ZipCode]
FROM [Students] AS [s]
    SELECT [s0].[Id], [s0].[Address_City], 
           [s0].[Address_Street], [s0].[Address_ZipCode]
    FROM [Students] AS [s0]
    WHERE [s0].[Address_ZipCode] IS NOT NULL OR 
          ([s0].[Address_Street] IS NOT NULL OR 
          [s0].[Address_City] IS NOT NULL)
) AS [t] ON [s].[Id] = [t].[Id]
4/6/2020 6:05:23 AM

Accepted Answer

This is a bug introduced by EF Core 3.0 new query processing pipeline, most likely related to the following breaking change Dependent entities sharing the table with the principal are now optional, which is supposed to fix some user requested scenarios, but in fact breaks many others.

It's currently tracked by #18299: Query on owned entity produces overly complicated SQL and unfortunately looks like won't be fixed in 3.1, so the people are expected to wait for 5.0 release. Meanwhile there is nothing you can do about it.

4/6/2020 9:08:32 AM

Popular Answer

You have mentioned the relation as "Owned" type. Owned type are always included when you are querying the parent object. See here for details.

You can use 'HasOne' relation, to avoid this.

Related Questions


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