Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
samisq opened this issue Feb 21, 2024 · 4 comments

Comments

@samisq
Copy link

samisq commented Feb 21, 2024

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

@ajcvickers
Copy link
Member

Note for team triage: also repros on SQL Server and still repros on latest daily.

@ajcvickers
Copy link
Member

@maumar Still repros on latest daily.

@maumar maumar added this to the 9.0.0 milestone Apr 12, 2024
@maumar
Copy link
Contributor

maumar commented Apr 12, 2024

when building SelectExpression from TableValuedFunctionExpression we put StoreFunction as ITableBase (and put it in table map).
Later, in the ApplyProjection step when we try to build shaper expression for the complex type, we rely on GetViewOrTableMappings from metadata, to find the table, and that resolves to a BlogMetadata table, which is not what we expect.

I can get the right table mapping by doing

complexProperty.ComplexType.ContainingEntityType.GetFunctionMappings().Single().Table;

but then the code blows up later when trying to find a column associated with a property on a complex type (FunctionColumnMappings got nothing in them)

@AndriySvyryd
Copy link
Member

Blocked by/duplicate of #34627

@AndriySvyryd AndriySvyryd modified the milestones: 9.0.0, Backlog Sep 6, 2024
@AndriySvyryd AndriySvyryd removed their assignment Sep 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants