2

Entity framework core seems to create very complex queries when configuring value objects with OwnsOne on the same table.

Entity: Restaurant.cs

public class Restaurant : Entity, IAggregateRoot
{
    public RestaurantId Id { get; private set; }

    public string Name { get; private set; }
    public Address Address { get; private set; }

    protected Restaurant()
    {

    }

    public Restaurant SetAddress(double lat, double lng, string street, string location, string zip, string country)
    {
        Address = new Address(lat, lng, street, location, zip, country);
        return this;
    }
}

Value object: Address.cs

public class Address : ValueObject
{
    public Point Location { get; set; }
    public string Street { get; private set; }
    public string City { get; private set; }
    public string Country { get; private set; }
    public string Zip { get; private set; }

    private Address() { }

    public Address(double lat, double lng, string street, string city, string zip, string country)
    {
        Location = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326).CreatePoint(new Coordinate(lng, lat));
        Street = street;
        City = city;
        Country = country;
        Zip = zip;
    }

    protected override IEnumerable<object> GetAtomicValues()
    {
        yield return Street;
        yield return City;
        yield return Country;
        yield return Zip;
    }
}

EF Config: RestaurantEntityTypeConfig.cs

internal class RestaurantEntityTypeConfig : IEntityTypeConfiguration<Restaurant>
{
    public void Configure(EntityTypeBuilder<Restaurant> builder)
    {
        builder.ToTable("Restaurant", SchemaNames.Restaurant);
        builder.HasKey(c => c.Id);
        builder.OwnsOne(c => c.Address, c=>
        {
            c.WithOwner();
        });
    }
}

Repository method:

public virtual async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, params public virtual async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
{
    var query = _dbContext.Set<T>().Where(predicate);
    query = includeProperties.Aggregate(query, (current, includeProperty) => current.Include(includeProperty));

    return await query.FirstOrDefaultAsync();
}

The query when selecting through repository looks like this:

SELECT TOP(1) [r].[Id], [r].[Name], [t].[Id], [t].[Address_City], [t].[Address_Country], [t].[Address_State], [t].[Address_Street], [t].[Address_ZipCode]
FROM [restaurant].[Restaurant] AS [r]
LEFT JOIN (
    SELECT [r0].[Id], [r0].[Address_City], [r0].[Address_Country], [r0].[Address_State], [r0].[Address_Street], [r0].[Address_ZipCode], [r1].[Id] AS [Id0]
    FROM [restaurant].[Restaurant] AS [r0]
    INNER JOIN [restaurant].[Restaurant] AS [r1] ON [r0].[Id] = [r1].[Id]
    WHERE [r0].[Address_ZipCode] IS NOT NULL OR ([r0].[Address_Street] IS NOT NULL OR ([r0].[Address_State] IS NOT NULL OR ([r0].[Address_Country] IS NOT NULL OR [r0].[Address_City] IS NOT NULL)))
) AS [t] ON [r].[Id] = [t].[Id]
WHERE [r].[Id] = @__p_0

The sql table looks like this:

Text

My expected result would be a flat query since the value object is persisted to the same sql table. Is this a bug of entity framework or am I missing a configuration?

Nando
  • 813
  • 2
  • 8
  • 18
  • 1
    You are doing nothing wrong. Please go search/ask/report here https://github.com/dotnet/efcore/issues. – Ivan Stoev Feb 18 '20 at 19:41
  • 1
    Thanks for the link. In fact there is already an open issue that is planed for november 2020 release. In the meantime there is a workaround by mapping the same table to a view (this goes only for non optional owned properties). https://github.com/dotnet/efcore/issues/18299 – Nando Feb 18 '20 at 22:20
  • Yeah, and looks like you can get it fixed sooner https://github.com/dotnet/efcore/issues/19932 – Ivan Stoev Feb 19 '20 at 07:13

0 Answers0