Skip to content

Entity with shadow property and nullable complex property with discriminator throws ArgumentOutOfRangeException when queried #37337

@peterwurzinger

Description

@peterwurzinger

Bug description

When configuring an entity that contains both

  • a nullable complex property needing a discriminator and
  • a shadow property

querying tracked instances of the configured entity throws an ArgumentOutOfRangeException. A quick inspection with Source Link indicates, that it somehow seems to lose track of the Discriminator property in ShadowValuesFactoryFactory.CreateReadShadowValueExpression, as only the manually configured shadow properties are present.

For context:
I encountered the problem with a real-life complex property that consisted of optional/nullable properties only, in combination with an entity-level Audit that would be applied to entities meeting a certain criteria by convention. So the use case is not too exotic.

I tried to reproduce it as concise as possible using the InMemory provider, but I observed the problem with the SqlServer provider as well. I think it's a provider-agnostic issue anyways.

Your code

#:package Microsoft.EntityFrameworkCore.InMemory@10.0.1
#:property PublishAot=false

using Microsoft.EntityFrameworkCore;

await using var context = new EntityContext();
await context.Database.EnsureCreatedAsync();

//Throws ArgumentOutOfRangeException
var entities = await context.Entities.ToArrayAsync();

public class EntityContext : DbContext
{
  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.UseInMemoryDatabase("ComplexPropertyRepro");

  public DbSet<Entity> Entities { get; set; }
  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
    var entity = modelBuilder.Entity<Entity>();
    entity.Property(p => p.Id);
    entity.HasKey(p => p.Id);

    var compl = entity.ComplexProperty(p => p.Prop);
    compl.Property(p => p.OptionalValue);
    compl.HasDiscriminator();

    //Imagine this being added via convetion to prepare some kind of entity-level audit
    entity.Property<string>("CreatedBy").IsRequired(false);
  }
}

public class Entity
{
  public Guid Id { get; set; }
  public OptionalComplexProperty? Prop { get; set; }
}

public class OptionalComplexProperty
{
  public bool? OptionalValue { get; set; }
}

Stack traces

Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at System.SZArrayHelper.get_Item[T](Int32 index)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ShadowValuesFactoryFactory.CreateReadShadowValueExpression(Expression parameter, IPropertyBase property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ShadowValuesFactoryFactory.CreateReadValueExpression(Expression parameter, IPropertyBase property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory.CreateSnapshotExpression(Type clrType, Expression parameter, Type[] types, IList`1 propertyBases)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory.CreateConstructorExpression(IRuntimeTypeBase structuralType, Expression parameter)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.StructuralTypeMaterializerInjector.CreateFullMaterializeExpression(ITypeBase concreteStructuralType, ValueTuple`5 materializeExpressionContext)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.StructuralTypeMaterializerInjector.MaterializeEntity(StructuralTypeShaperExpression shaper, ParameterExpression materializationContextVariable, ParameterExpression concreteEntityTypeVariable, ParameterExpression instanceVariable, ParameterExpression entryVariable)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.StructuralTypeMaterializerInjector.ProcessStructuralTypeShaper(StructuralTypeShaperExpression shaper)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.StructuralTypeMaterializerInjector.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.StructuralTypeMaterializerInjector.Inject(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.InjectStructuralTypeMaterializers(Expression expression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.ShaperExpressionProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.ShaperExpressionProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   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.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IAsyncEnumerable<TEntity>.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in E:\ComplexPropertyRepro\Program.cs:line 10
   at Program.<Main>$(String[] args) in E:\ComplexPropertyRepro\Program.cs:line 10
   at Program.<Main>(String[] args)

Verbose output


EF Core version

10.0.1

Database provider

Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.InMemory

Target framework

net10.0

Operating system

Windows 11

IDE

Visual Studio 2026 and .NET SDK on CLI

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions