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

Problem with ComplexProperty in EF9, when using the TPT approach #35392

Open
NikitaReut7 opened this issue Dec 30, 2024 · 2 comments
Open

Problem with ComplexProperty in EF9, when using the TPT approach #35392

NikitaReut7 opened this issue Dec 30, 2024 · 2 comments

Comments

@NikitaReut7
Copy link

Include your code

Good afternoon, I get an error System.InvalidOperationException: “Sequence contains more than one element” when I try to get data from the database, as I noticed, the problem is related to ComplexProperty (for example, if you change Money to a class and use OwnsOne, everything is correctly formed and returned from the database without errors). NOTE that this error appeared when I switched to .net 9 and ef9, while working with .net 8 and ef 8.0.8 there was no such error.

Here is a link to the repository with the reproduced problem: https://github.com/NikitaReut7/WebApp

Here is a link to a repository with the same code but for .net8 and ef8, but everything works here: https://github.com/NikitaReut7/WebAppNet8

Include stack traces

System.InvalidOperationException
HResult=0x80131509
Сообщение = Sequence contains more than one element
Источник = System.Linq
Трассировка стека:
в System.Linq.ThrowHelper.ThrowMoreThanOneElementException()
в System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable1 source, Boolean& found) в System.Linq.Enumerable.Single[TSource](IEnumerable1 source)
в Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.GenerateComplexPropertyShaperExpression(StructuralTypeProjectionExpression containerProjection, IComplexProperty complexProperty)
в Microsoft.EntityFrameworkCore.Query.StructuralTypeProjectionExpression.BindComplexProperty(IComplexProperty complexProperty)
в Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.g__ProcessType|60_19(StructuralTypeProjectionExpression typeProjection, <>c__DisplayClass60_6& )
в Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.g__AddStructuralTypeProjection|60_0(StructuralTypeProjectionExpression projection)
в Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ApplyProjection(Expression shaperExpression, ResultCardinality resultCardinality, QuerySplittingBehavior querySplittingBehavior)
в Microsoft.EntityFrameworkCore.Query.Internal.SelectExpressionProjectionApplyingExpressionVisitor.VisitExtension(Expression extensionExpression)
в Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPostprocessor.Process(Expression query)
в Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlQueryTranslationPostprocessor.Process(Expression query)
в Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression query)
в Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
в Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass11_01.<ExecuteCore>b__0() в Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compiler)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
в Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
в Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1.GetAsyncEnumerator(CancellationToken cancellationToken) в Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken)
в System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable1.GetAsyncEnumerator() в Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__671.MoveNext()
в Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.d__681.MoveNext() в WebApp.Controllers.EntitiesController.<GetDerivedEntitiesB>d__4.MoveNext() в C:\Users\Nikita\Desktop\WebApp-master\WebApplication\Controllers\EntitiesController.cs:строка 38 в Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.<Execute>d__0.MoveNext() в System.Runtime.CompilerServices.ValueTaskAwaiter1.GetResult()
в Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<g__Awaited|12_0>d.MoveNext()
в Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<g__Awaited|10_0>d.MoveNext()

Include provider and version information

EF Core version: Microsoft.EntityFrameworkCore 9.0
Database provider: Npgsql.EntityFrameworkCore.PostgreSQL 9.0.2
Target framework: NET 9.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.12.3

@roji
Copy link
Member

roji commented Dec 30, 2024

@NikitaReut7 I can confirm that I see the error, thanks. Note that this is likely dup of #35025, although that issue is about TPC and asserts that TPT is working correctly, whereas this issue is about TPT.

Although I can indeed see the provided repro failing on EF 9 and running on EF 8 (so a regression, as written above), the minimal repro below also fails on EF 8. In any case, we're planning a big push on complex type support for 10 - am putting this in that milestone to properly fix.

Minimal reproawait using var context = new BlogContext(); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); var a = await context.Set<BaseEntity>().ToArrayAsync(); public class BlogContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<BaseEntity>(builder => { builder.ToTable("BaseEntities"); builder.HasKey(e => e.BaseNumber); builder.Property(e => e.Name).IsRequired().HasMaxLength(100); }); modelBuilder.Entity<DerivedEntityA>(builder => { builder.ToTable("DerivedEntitiesA"); builder.Property(e => e.PropertyA).IsRequired().HasMaxLength(200); builder.OwnsOne(c => c.Point, point => { point.Property(c => c.Id).HasColumnName("Id"); point.Property(c => c.Value).HasColumnName("Value"); }); builder.ComplexProperty(c => c.Money, point => { point.Property(c => c.Count).HasColumnName("Count"); point.Property(c => c.MoneyString).HasColumnName("MoneyString"); }); }); modelBuilder.Entity<DerivedEntityB>(builder => { builder.ToTable("DerivedEntitiesB"); builder.Property(e => e.PropertyB).IsRequired().HasMaxLength(300); }); modelBuilder.Entity<DerivedEntityC>(builder => { builder.ToTable("DerivedEntitiesC"); builder.Property(e => e.PropertyC).IsRequired().HasMaxLength(300); builder.OwnsOne(c => c.Point, point => { point.Property(c => c.Id).HasColumnName("Id"); point.Property(c => c.Value).HasColumnName("Value"); }); builder.ComplexProperty(c => c.Money, point => { point.Property(c => c.Count).HasColumnName("Count"); point.Property(c => c.MoneyString).HasColumnName("MoneyString"); }); }); } } public abstract class BaseEntity { public string BaseNumber { get; } public string? Name { get; set; } } public class DerivedEntityA : BaseEntity { public string PropertyA { get; set; } public Point? Point { get; set; } public Money Money { get; set; } } public class DerivedEntityB : DerivedEntityA { public string PropertyB { get; set; } } public class DerivedEntityC : BaseEntity { public Point? Point { get; set; } public Money Money { get; set; } public string PropertyC { get; set; } } public struct Money { public string Count { get; private set; } public string MoneyString { get; private set; } } public class Point { public int Id { get; } public string Value { get; } }

@roji
Copy link
Member

roji commented Dec 30, 2024

@cincuranet assigning to you as a complex type query issue; I recommend looking into this together with #35025.

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

3 participants