efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Exception when using ComplexProperty on entity that's mapped to a Table-Valued function or a View

Open samisq opened this issue 1 year ago • 0 comments

Runnable project: ComplexPropertyBug.zip

Code snippet

using Microsoft.EntityFrameworkCore;

await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.MigrateAsync();

await ctx.CalculateBlogMetadata(123).ToListAsync();

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public IQueryable<BlogMetadata> CalculateBlogMetadata(int param1)
        => FromExpression(() => CalculateBlogMetadata(param1));
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDbFunction(() => CalculateBlogMetadata(default));
        var eb = modelBuilder.Entity<BlogMetadata>();
        eb.HasKey(x => x.BlogId);
        eb.ComplexProperty(x => x.Metadata);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseNpgsql("Host=localhost;Database=my_test_db;Username=postgres;Password=password");
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

public class BlogMetadata
{
    public int BlogId { get; init; }
    public required Metadata Metadata { get; init; }
}

public record Metadata(int CommentCount, int LikeCount);

The following exception is thrown when running the attached code project:

Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'Table: BlogMetadata  Key: PK_BlogMetadata {'BlogId'} PrimaryKey' 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)
   at Microsoft.EntityFrameworkCore.Query.StructuralTypeProjectionExpression.BindComplexProperty(IComplexProperty complexProperty)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.<ApplyProjection>g__ProcessType|64_19(StructuralTypeProjectionExpression typeProjection, <>c__DisplayClass64_6&)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.<ApplyProjection>g__AddStructuralTypeProjection|64_0(StructuralTypeProjectionExpression projection)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ApplyProjection(Expression shaperExpression, ResultCardinality resultCardinality, QuerySplittingBehavior querySplittingBehavior)
   at Microsoft.EntityFrameworkCore.Query.Internal.SelectExpressionProjectionApplyingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPostprocessor.Process(Expression query)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlQueryTranslationPostprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in /Users/samisaqer/ComplexPropertyBug/ComplexPropertyBug/ComplexPropertyBug/Program.cs:line 7
   at Program.<Main>$(String[] args) in /Users/samisaqer/ComplexPropertyBug/ComplexPropertyBug/ComplexPropertyBug/Program.cs:line 7
   at Program.<Main>(String[] args)

Note: similar issue happens when using views, but the exception is slightly different in that case:

Unhandled exception. System.InvalidOperationException: Sequence contains no elements
   at System.Linq.ThrowHelper.ThrowNoElementsException()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.GenerateComplexPropertyShaperExpression(StructuralTypeProjectionExpression containerProjection, IComplexProperty complexProperty)
   at Microsoft.EntityFrameworkCore.Query.StructuralTypeProjectionExpression.BindComplexProperty(IComplexProperty complexProperty)
...

Provider and version information

EF Core version: 8.0.2 Database provider: Npgsql.EntityFrameworkCore.PostgreSQL Target framework: .NET 8.0 Operating system: Mac OS

samisq avatar Feb 21 '24 04:02 samisq