dotnet / dotnet/efcore

Deleting item from JSON-owned collection with nested owned relational children throws: '__synthesizedOrdinal' is read-only after it has been saved

Open
#37,208 1 comment 2 reactions 1 assignee Claimed by @AndriySvyryd View on GitHub
area-json area-owned-entities area-save-changes customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

### Bug description

When using EF Core’s JSON columns (ToJson()) with an OwnsMany collection, deleting elements works only for the first or last element in the list.
Deleting an inner element throws:

System.InvalidOperationException: The property 'XyzTermLanguageWrapper.XyzTerm__synthesizedOrdinal'
is defined as read-only after it has been saved, but its value has been modified or marked as modified.

This happens only when the JSON-stored owned entity (XyzTerm) itself contains another OwnsMany collection. Otherwise this seems to work.

### Your code

```csharp
public class AppDbContext : DbContext
{
public DbSet Dockets => Set();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(n =>
{
n.HasKey(x => x.Id);

n.OwnsMany(e => e.Terms, t =>
{
t.ToJson(); // Stored as JSON array

t.OwnsMany(nt => nt.Texts, tt =>
{
});
});
});
}
}

public class Docket
{
public long Id { get; set; }
public List Terms { get; set; } = new();
}

public class XyzTerm
{
public int ClassNo { get; set; }
public Guid? CustomId { get; set; }

public List Texts { get; set; } = new();
}

public class XyzTermLanguageWrapper
{
public string Language { get; set; }
public string Text { get; set; }
}

// This trows
var docket = await db.Dockets.FirstAsync();

var termToDelete = docket.Terms
.First(t => t.CustomId == someInnerCustomId); // inner element, not first/last

docket.Terms.Remove(termToDelete);

await db.SaveChangesAsync(); // throws
```

### Stack traces

```text
ERROR 2025-11-19 21:27:54,334 [22 ] Microsoft.EntityFrameworkCore.Update - An exception occurred in the database while saving changes for context type 'IPSweb.EntityFrameworkCore.REDACTED'.
System.InvalidOperationException: The property 'XyzTermLanguageWrapper.XyzTerm__synthesizedOrdinal' is defined as read-only after it has been saved, but its value has been modified or marked as modified.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave(Boolean cascadeChanges)
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)
System.InvalidOperationException: The property 'XyzTermLanguageWrapper.XyzTerm__synthesizedOrdinal' is defined as read-only after it has been saved, but its value has been modified or marked as modified.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave(Boolean cascadeChanges)
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)
```

### Verbose output

```text

```

### EF Core version

9.0.5

### Database provider

Npgsql.EntityFrameworkCore.PostgreSQL

### Target framework

.NET 9

### Operating system

MacOS 26.1

### IDE

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.