Owned json collection remove add new and readd old throws InvalidOperationException
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- PR merge metrics
- PR metrics pending
Description
### Bug description
When removing and readding an owned entity from a json collection while also adding another, SaveChangesAsync will throw an InvalidOperationException.
`The instance of entity type 'OwnedType' cannot be tracked because another instance with the key value '{EntityTypeId: 237dcd95-8ed4-4239-b107-96c87ee76947, __synthesizedOrdinal: 1}' is already being tracked. When replacing owned entities, modify the properties without changing the instance or detach the previous owned entity entry first.`
### Your code
```csharp
using Microsoft.EntityFrameworkCore;
var options = new DbContextOptionsBuilder()
.EnableSensitiveDataLogging()
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MyDbContext;Trusted_Connection=True;")
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information)
.Options;
using (var context = new MyDbContext(options))
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var entity = new EntityType
{
Id = Guid.NewGuid(),
OwnedTypes = [
new OwnedType { Id = 1, Name = "OwnedType1" },
]
};
context.Add(entity);
await context.SaveChangesAsync();
var old = entity.OwnedTypes[0];
entity.OwnedTypes.Remove(old);
entity.OwnedTypes.Add(new OwnedType { Id = 2, Name = "OwnedType2" });
entity.OwnedTypes.Add(old);
await context.SaveChangesAsync(); // Throws
}
internal class MyDbContext(DbContextOptions options) : DbContext(options)
{
public DbSet EntityTypes => Set();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var type = modelBuilder.Entity();
modelBuilder.Entity().OwnsMany(x => x.OwnedTypes, cfg => cfg.ToJson());
}
}
public class EntityType
{
public Guid Id { get; set; }
public Guid PartitionKey { get; set; }
public List OwnedTypes { get; set; } = new List();
}
public class OwnedType
{
public int Id { get; set; }
public string Name { get; set; } = null!;
}
```
### Stack traces
```text
Unhandled exception. System.InvalidOperationException: The instance of entity type 'OwnedType' cannot be tracked because another instance with the key value '{EntityTypeId: 237dcd95-8ed4-4239-b107-96c87ee76947, __synthesizedOrdinal: 1}' is already being tracked. When replacing owned entities, modify the properties without changing the instance or detach the previous owned entity entry first.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NullableKeyIdentityMap`1.Add(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.UpdateIdentityMap(InternalEntityEntry entry, IKey key)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IEnumerable`1 containingPrincipalKeys, IEnumerable`1 containingForeignKeys, Object oldValue, Object newValue)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IEnumerable`1 keys, IEnumerable`1 foreignKeys, Object oldValue, Object newValue)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectKeyChange(IInternalEntry entry, IProperty property)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.PropertyChanged(IInternalEntry entry, IPropertyBase propertyBase, Boolean setModified)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.PropertyChanged(IInternalEntry entry, IPropertyBase property, Boolean setModified)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.OnPropertyChanged(IPropertyBase propertyBase, Object value, Boolean setModified)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.OnPropertyChanged(IPropertyBase propertyBase, Object value, Boolean setModified)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.SetProperty(IPropertyBase propertyBase, Object value, Boolean isMaterialization, Boolean setModified, Boolean isCascadeDelete, CurrentValueType valueType)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.SetStoreGeneratedValue(IProperty property, Object value, Boolean setModified)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.WriteJsonObject(Utf8JsonWriter writer, IInternalEntry parentEntry, IInternalEntry entry, ITypeBase structuralType, Nullable`1 ordinal)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.WriteJson(Utf8JsonWriter writer, Object value, IInternalEntry parentEntry, IPropertyBase property, Nullable`1 ordinal, Boolean isCollection, Boolean isTopLevel)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.WriteJson(Utf8JsonWriter writer, Object value, IInternalEntry parentEntry, IPropertyBase property, Nullable`1 ordinal, Boolean isCollection, Boolean isTopLevel)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.g__HandleJson|40_8(List`1 columnModifications, <>c__DisplayClass40_0&)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.GenerateColumnModifications()
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.<>c.b__33_0(ModificationCommand command)
at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.Update.ModificationCommand.get_ColumnModifications()
at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.CreateCommandBatches(IEnumerable`1 commandSet, Boolean moreCommandSets, Boolean assertColumnModification, ParameterNameGenerator parameterNameGenerator)+MoveNext()
at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.BatchCommands(IList`1 entries, IUpdateAdapter updateAdapter)+MoveNext()
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.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.$(String[] args) in C:\Repos\ConsoleApp3\ConsoleApp3\Program.cs:line 32
at Program.(String[] args
```
### EF Core version
10.0.5
### Database provider
Microsoft.EntityFrameworkCore.SqlServer
### Target framework
.NET 10
### Operating system
W11
### IDE
VS2026
Contributor guide
Assessment
This issue has not been assessed yet.