dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.78k stars 3.19k forks source link

Error querying on complex type whose container is mapped to a table and a view #34706

Open roji opened 1 month ago

roji commented 1 month ago

The following code:

await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

_ = await context.Blogs.Where(b => b.ComplexThing.Prop1 == 8).ToListAsync();

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Server=localhost;Database=test;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .ToTable("Blogs")
            .ToView("BlogsView")
            .ComplexProperty(b => b.ComplexThing);
    }
}

public class Blog
{
    public int Id { get; set; }
    public ComplexThing ComplexThing { get; set; }
}

public class ComplexThing
{
    public int Prop1 { get; set; }
    public int Prop2 { get; set; }
}

... throws:

Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'DefaultTable: Blog' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.GenerateComplexPropertyShaperExpression(StructuralTypeProjectionExpression containerProjection, IComplexProperty complexProperty) in /Users/roji/projects/efcore/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs:line 2672
   at Microsoft.EntityFrameworkCore.Query.StructuralTypeProjectionExpression.BindComplexProperty(IComplexProperty complexProperty) in /Users/roji/projects/efcore/src/EFCore.Relational/Query/StructuralTypeProjectionExpression.cs:line 375
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.BindComplexProperty(StructuralTypeReferenceExpression typeReference, IComplexProperty complexProperty) in /Users/roji/projects/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs:line 1331
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TryBindMember(Expression source, MemberIdentity member, Expression& expression, IPropertyBase& property) in /Users/roji/projects/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs:line 1208

This is because calling GetViewOrTableMappings() on the complex type returns only the table mapping - this seems like a metadata issue.

Once this fixed, GenerateComplexPropertyShaperExpression would need to be fixed to support this scenario as well.

roji commented 1 month ago

The metadata support is already covered by #34627. Once that's done, this issue tracks doing the proper adjustments to GenerateComplexPropertyShaperExpression.

Adjustments will also be needed for property handling of ExecuteUpdate when a complex type is referenced as the property to change, and there's a view mapping; see test Update_complex_type_type_with_view_mapping.