Skip to content
New issue

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

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

Already on GitHub? # 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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants