-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
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