Bug description
This may be resolved with the same fix as #37377; however, posting to be sure.
When deleting an item from a ComplexCollection, that Contains an array, an error is thrown.
Using the code below, calling SaveChanges(), results in an exception. What is unusual, is the save still goes through and the database result is correct.
Your code
#:package Microsoft.EntityFrameworkCore@10.0.2
#:package Npgsql.EntityFrameworkCore.PostgreSQL@10.0.0
#:package Testcontainers@4.10.0
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using EfCore10Regression.Tests;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;
using static EfCore10Regression.Tests.Models;
var fixture = new PostgresContainerFixture();
await fixture.InitializeAsync();
Console.WriteLine($"Postgres started. ConnectionString={fixture.ConnectionString}");
Console.WriteLine($"Logging SQL to: {fixture.LogFilePath}");
await using (var ctx = fixture.CreateContext())
{
var modelBs = new List<ModelB>
{
new() {
Id = 1,
ModelCs = []
}
};
ctx.Models.Add(new ModelA
{
Id = 0,
ModelBs = modelBs
});
await ctx.SaveChangesAsync();
}
await using var context = fixture.CreateContext();
var rawData = await context.Models.SingleAsync();
Console.WriteLine($"Nbr items before {rawData.ModelBs.Count}");
rawData.ModelBs = [.. rawData.ModelBs.Where(x => x.Id != 1)];
Console.WriteLine($"Nbr items after {rawData.ModelBs.Count}");
await context.SaveChangesAsync();
Console.WriteLine("SUCCESS!!");
Console.ReadLine();
await fixture.DisposeAsync();
namespace EfCore10Regression.Tests
{
public class RegressionDbContext(DbContextOptions<RegressionDbContext> options) : DbContext(options)
{
public DbSet<Models.ModelA> Models => Set<Models.ModelA>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Models.ModelA>(b => b.ComplexCollection(c => c.ModelBs, c =>
{
c.ToJson();
}));
}
}
public static class Models
{
public class ModelA
{
public int Id { get; set; }
public List<ModelB> ModelBs { get; set; } = [];
}
public class ModelB
{
public int Id { get; set; }
public List<ModelC> ModelCs { get; set; } = [];
}
public record ModelC
{
public Guid Id { get; set; }
}
}
public class PostgresContainerFixture : IAsyncLifetime
{
private readonly IContainer _pgContainer;
private StreamWriter? _logWriter;
public string ConnectionString { get; private set; } = string.Empty;
public string? LogFilePath { get; private set; }
public PostgresContainerFixture()
{
_pgContainer = new ContainerBuilder("postgis/postgis:latest")
.WithPortBinding(5432, assignRandomHostPort: true)
.WithEnvironment("POSTGRES_PASSWORD", "postgres")
.WithEnvironment("POSTGRES_USER", "postgres")
.WithEnvironment("POSTGRES_DB", "testdb")
.WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(5432))
.Build();
}
public async Task InitializeAsync()
{
await _pgContainer.StartAsync();
var host = _pgContainer.Hostname;
var port = _pgContainer.GetMappedPublicPort(5432);
ConnectionString = new NpgsqlConnectionStringBuilder
{
Host = host,
Port = port,
Username = "postgres",
Password = "postgres",
Database = "testdb"
}.ToString();
LogFilePath = Path.Combine(Path.GetTempPath(), $"efcore-sql-{Guid.NewGuid():N}.log");
_logWriter = new StreamWriter(File.Open(LogFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
AutoFlush = true
};
}
public async Task DisposeAsync()
{
await _pgContainer.StopAsync();
await _pgContainer.DisposeAsync();
_logWriter?.Dispose();
}
public RegressionDbContext CreateContext()
{
var optionsBuilder = new DbContextOptionsBuilder<RegressionDbContext>()
.UseNpgsql(ConnectionString, a => a.UseNetTopologySuite())
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
if (_logWriter is not null)
{
optionsBuilder.LogTo(_logWriter.WriteLine, LogLevel.Information);
}
var ctx = new RegressionDbContext(optionsBuilder.Options);
ctx.Database.EnsureCreated();
return ctx;
}
}
public interface IAsyncLifetime
{
Task InitializeAsync();
Task DisposeAsync();
}
}
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 lambda_method39(Closure, ModelA, IReadOnlyList`1)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.ReadPropertyValue(IPropertyBase propertyBase)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalComplexEntry.ReadPropertyValue(IPropertyBase propertyBase)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.get_Item(IPropertyBase propertyBase)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.InternalComplexCollectionEntry.SetState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalComplexEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, Nullable`1 fallbackState)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.AcceptChanges()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalComplexEntry.AcceptChanges()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.InternalComplexCollectionEntry.AcceptChanges()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.AcceptChanges()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.AcceptChanges()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.AcceptAllChanges(IReadOnlyList`1 changedEntries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in C:\Users\brad\Downloads\EfCore10Regression.Tests_TB\EfCore10Regression.Tests\QueryRegressionTests.cs:line 45
at Program.<Main>$(String[] args) in C:\Users\brad\Downloads\EfCore10Regression.Tests_TB\EfCore10Regression.Tests\QueryRegressionTests.cs:line 49
at Program.<Main>(String[] args)
Verbose output
EF Core version
10.0.2
Database provider
Npgsql.EntityFrameworkCore.PostgreSQL
Target framework
.NET 10
Operating system
No response
IDE
No response
Bug description
This may be resolved with the same fix as #37377; however, posting to be sure.
When deleting an item from a ComplexCollection, that Contains an array, an error is thrown.
Using the code below, calling SaveChanges(), results in an exception. What is unusual, is the save still goes through and the database result is correct.
Your code
Stack traces
Verbose output
EF Core version
10.0.2
Database provider
Npgsql.EntityFrameworkCore.PostgreSQL
Target framework
.NET 10
Operating system
No response
IDE
No response