Skip to content

Projection of entity with complex collection throws exception #37725

@ArnaudB88

Description

@ArnaudB88

Bug description

I am trying to map an entity to a dto (with Automapper) and it gives an exception:

The program executed an instruction that was thought to be unreachable.

Why

As suggested in the EfCore 10 release notes, we are migrating from owned entities (saved as json) to complex entity types. This results in several problems, and the bug described here is one of them.
The described scenario worked fine with owned entities.

Scenario

We use the repository pattern and Automapper to retrieve and update data in our SQL database. We have 2 methods of mapping an entity to a dto:

  • through a projection starting from another entity (map Foo to FooDto starting from the dbset of Bars with a filter and projection) -> fails
  • directly starting from the target entity (map Foo to FooDto starting from the dbset of Foos) -> works fine

Both methods are set below in code.
(see code for a better understanding)

Your code

//entities
public partial class Project
{
    public Guid Id { get; set; }

    public IList<KolomMetadata> KolomMetadata { get; set; }
}
public partial class Werkpakket
{
    public Guid Id { get; set; }
    public Guid ProjectId { get; set; }

    [Ignore]
    public virtual Project Project { get; set; }

    public IList<KolomMetadata> KolomMetadata { get; set; }
}

//Mappings
public partial class ProjectMap
    : IEntityTypeConfiguration<ClientName.ProjectName.Domain.Entities.Project>
{
    public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<ClientName.ProjectName.Domain.Entities.Project> builder)
    {
        builder.ToTable("Project", "dbo");
        builder.HasKey(t => t.Id);
		
        builder.ComplexCollection(t => t.KolomMetadata, builder => builder.ToJson().Configure());		
		//Note: the Configure() method sets the property names of the KolomMetadata to camelCase
	}
}

public partial class WerkpakketMap
    : IEntityTypeConfiguration<ClientName.ProjectName.Domain.Entities.Werkpakket>
{
    public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<ClientName.ProjectName.Domain.Entities.Werkpakket> builder)
    {
        builder.ToTable("Werkpakket", "dbo");
        builder.HasKey(t => t.Id);
        builder.Property(t => t.ProjectId)
            .IsRequired()
            .HasColumnName("ProjectId")
            .HasColumnType("uniqueidentifier");
        builder.HasOne(t => t.Project)
            .WithMany(t => t.Werkpakkets)
            .HasForeignKey(d => d.ProjectId)
            .HasConstraintName("FK_Werkpakket_Project");
			
        builder.ComplexCollection(t => t.KolomMetadata, builder => builder.ToJson().Configure());
	}
}

//AutoMapper MapperConfiguration contains
AutoMapper.CreateMap<Werkpakket, WerkpakketOverviewDto>()
  .IncludeBase<IWithKolomMetadata, DtoBaseWithKolomMetadata>();
  
CreateMap<IWithKolomMetadata, DtoBaseWithValidatedFieldDto>(MemberList.None)
    .Ignore(dst => dst.GevalideerdDoorPv)
    .Ignore(dst => dst.GevalideerdDoorIntern)
    .Ignore(dst => dst.Description);
			
//Scenario 1: Throws exception
Guid projectId = Guid.NewGuid();
Expression<Func<T, bool>> filter = p => p.Id == projectId;
Expression<Func<T, TOfProperty>> projection = p => p.Werkpakkets.FirstOrDefault();

var query = dbContext.Set<Project>.AsQueryable()
  .Where(filter)
  .AsNoTracking() //read only query
  .Select(projection)
  .ProjectTo<TDto>(MapperConfiguration); //based on AutoMapper mappings
  
var expression = query.Expression; //see result below
var result = query.FirstOrDefaultAsync(); //Throws exception


//Expression:
{[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].TagWith("Method: EntityFrameworkGenericTemporalRepositoryTests.FirstOrDefaultAsDtoAsync_Should_Work_ForTemporalAsOfWithNavProps() at line 369").Where(p => (p.Id == value(ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericTemporalRepositoryTests+<>c__DisplayClass9_0).projectId)).AsNoTracking().Select(p => p.Werkpakkets.FirstOrDefault()).Select(dtoWerkpakket => new WerkpakketOverviewDto() {Naam = dtoWerkpakket.Naam, Volgnummer = dtoWerkpakket.Volgnummer, IndicatiefBudget = dtoWerkpakket.IndicatiefBudget, LaatsteWijzigingDatum = dtoWerkpakket.LaatsteWijzigingDatum, LaatsteWijzigingDoor = dtoWerkpakket.LaatsteWijzigingDoor, VerwijderdDatum = dtoWerkpakket.VerwijderdDatum, VerwijderdDoor = dtoWerkpakket.VerwijderdDoor, KolomMetadata = dtoWerkpakket.KolomMetadata, Id = dtoWerkpakket.Id})}
    Arguments: Count = 2
    CanReduce: false
    DebugView: ".Call System.Linq.Queryable.Select(\r\n    .Call System.Linq.Queryable.Select(\r\n        .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking(.Call System.Linq.Queryable.Where(\r\n                .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.TagWith(\r\n                    .Extension<Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression>,\r\n                    \"Method: EntityFrameworkGenericTemporalRepositoryTests.FirstOrDefaultAsDtoAsync_Should_Work_ForTemporalAsOfWithNavProps() at line 369\")\r\n                ,\r\n                '(.Lambda #Lambda1<System.Func`2[ClientName.ProjectName.Domain.Entities.Project,System.Boolean]>))),\r\n        '(.Lambda #Lambda2<System.Func`2[ClientName.ProjectName.Domain.Entities.Project,ClientName.ProjectName.Domain.Entities.Werkpakket]>))\r\n    ,\r\n    '(.Lambda #Lambda3<System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto]>))\r\n\r\n.Lambda #Lambda1<
System.Func`2[ClientName.ProjectName.Domain.Enti..."
    Method: {System.Linq.IQueryable`1[ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto] Select[Werkpakket,WerkpakketOverviewDto](System.Linq.IQueryable`1[ClientName.ProjectName.Domain.Entities.Werkpakket], System.Linq.Expressions.Expression`1[System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto]])}
    NodeType: Call
    Object: null
    Type: {Name = "IQueryable`1" FullName = "System.Linq.IQueryable`1[[ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto, ClientName.ProjectName.Dtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
		
//Scenario 2: Works fine

Guid werkpakketId = Guid.NewGuid();
Expression<Func<T, bool>> filter = w => w.Id == werkpakketId;

dbContext.Set<Werkpakket>.AsQueryable()
  .Where(filter)
  .AsNoTracking() //read only query
  .ProjectTo<TDto>(MapperConfiguration); //based on AutoMapper mappings
  
var expression = query.Expression; //see result below
var result = query.FirstOrDefaultAsync(); //works
	

//Expression:
{[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].TagWith("Method: EntityFrameworkGenericTemporalRepositoryTests.FirstOrDefaultAsDtoAsync_Should_Work_ForTemporalAsOfWithNavProps() at line 366").Where(p => (p.Id == value(ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericTemporalRepositoryTests+<>c__DisplayClass9_0).werkpakketId)).AsNoTracking().Select(dtoWerkpakket => new WerkpakketOverviewDto() {Naam = dtoWerkpakket.Naam, Volgnummer = dtoWerkpakket.Volgnummer, IndicatiefBudget = dtoWerkpakket.IndicatiefBudget, LaatsteWijzigingDatum = dtoWerkpakket.LaatsteWijzigingDatum, LaatsteWijzigingDoor = dtoWerkpakket.LaatsteWijzigingDoor, VerwijderdDatum = dtoWerkpakket.VerwijderdDatum, VerwijderdDoor = dtoWerkpakket.VerwijderdDoor, KolomMetadata = dtoWerkpakket.KolomMetadata, Id = dtoWerkpakket.Id})}
    Arguments: Count = 2
    CanReduce: false
    DebugView: ".Call System.Linq.Queryable.Select(\r\n    .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking(.Call System.Linq.Queryable.Where(\r\n            .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.TagWith(\r\n                .Extension<Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression>,\r\n                \"Method: EntityFrameworkGenericTemporalRepositoryTests.FirstOrDefaultAsDtoAsync_Should_Work_ForTemporalAsOfWithNavProps() at line 366\")\r\n            ,\r\n            '(.Lambda #Lambda1<System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,System.Boolean]>))),\r\n    '(.Lambda #Lambda2<System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto]>))\r\n\r\n.Lambda #Lambda1<System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,System.Boolean]>(ClientName.ProjectName.Domain.Entities.Werkpakket $p)\r\n{\r\n    $p.Id == .Constant<ClientName.ProjectName.Tests.RepositoryTests.EntityFramewor
kGenericTemporalRepositoryTests+<>c__Di..."
    Method: {System.Linq.IQueryable`1[ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto] Select[Werkpakket,WerkpakketOverviewDto](System.Linq.IQueryable`1[ClientName.ProjectName.Domain.Entities.Werkpakket], System.Linq.Expressions.Expression`1[System.Func`2[ClientName.ProjectName.Domain.Entities.Werkpakket,ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto]])}
    NodeType: Call
    Object: null
    Type: {Name = "IQueryable`1" FullName = "System.Linq.IQueryable`1[[ClientName.ProjectName.Dtos.Werkpakketten.WerkpakketOverviewDto, ClientName.ProjectName.Dtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

Stack traces

System.Diagnostics.UnreachableException
  HResult=0x80131500
  Message=The program executed an instruction that was thought to be unreachable.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ClientProjectionRemappingExpressionVisitor.VisitExtension(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ClientProjectionRemappingExpressionVisitor.VisitExtension(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
   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 Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerQueryTranslationPostprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](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__DisplayClass11_0`1.<ExecuteCore>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
   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.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at ClientName.ProjectName.Repositories.EntityFrameworkGenericRepository`1.FirstOrDefaultAsDtoAsync[TDto,TOfProperty](Expression`1 filter, Expression`1 projection, Func`2 orderBy) in C:\Projects\ClientName\ProjectName\ClientName.ProjectName.Repositories\EntityFrameworkGenericRepository.cs:line 304
   at ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericTemporalRepositoryTests.<FirstOrDefaultAsDtoAsync_Should_Work_ForTemporalAsOfWithNavProps>d__9.MoveNext() in C:\Projects\ClientName\ProjectName\ClientName.ProjectName.Tests\RepositoryTests\EntityFrameworkGenericTemporalRepositoryTests.cs:line 369
   at Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.<ExecuteInternalAsync>d__55.MoveNext()

EF Core version

10.0.3

Database provider

Microsoft.EntityFrameworkCore.SqlServer

Target framework

.NET 10

Operating system

Windows 11

IDE

Visual Studio 2026 18.2.1

Metadata

Metadata

Assignees

Type

No fields configured for Bug.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions