diff --git a/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs b/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs index d9d8dea9f5f..e0760b84bf2 100644 --- a/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs +++ b/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs @@ -72,6 +72,25 @@ private static void ThrowIfKeyChanged(IInternalEntry entry, IProperty property) if (property.IsKey() && property.GetAfterSaveBehavior() == PropertySaveBehavior.Throw) { + // Allow key changes for owned entities when changing parent relationship in collections + // This is necessary when moving owned entities between different parent entity collections + if (entry is InternalEntityEntry entityEntry) + { + // Check if this property is part of an ownership foreign key + var entityType = entityEntry.EntityType; + var ownershipForeignKey = entityType.FindOwnership(); + if (ownershipForeignKey != null && ownershipForeignKey.Properties.Contains(property)) + { + // Only allow the foreign key property change for owned entities in collection navigations + // One-to-one owned relationships should still throw as they have different semantics + var principalToDependent = ownershipForeignKey.PrincipalToDependent; + if (principalToDependent != null && principalToDependent.IsCollection) + { + return; + } + } + } + throw new InvalidOperationException(CoreStrings.KeyReadOnly(property.Name, entry.StructuralType.DisplayName())); } } diff --git a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs index 1a7342cd017..7d750cfdafc 100644 --- a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs +++ b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs @@ -1356,6 +1356,28 @@ private static void UndeleteDependent( if (dependentEntry.EntityState == EntityState.Deleted && principalEntry.EntityState is EntityState.Unchanged or EntityState.Modified) { + // For owned entities in collections, if the foreign key properties are part of the primary key, + // changing the parent means the primary key changes, so we need to treat this as + // a new entity (Added) rather than a modified entity + var entityType = dependentEntry.EntityType; + var ownership = entityType.FindOwnership(); + if (ownership != null) + { + // Only apply this logic to owned entities in collection navigations + var principalToDependent = ownership.PrincipalToDependent; + if (principalToDependent != null && principalToDependent.IsCollection) + { + // Check if any ownership foreign key properties are part of the primary key + var keyProperties = entityType.FindPrimaryKey()?.Properties ?? Array.Empty(); + var ownershipFKProperties = ownership.Properties; + if (keyProperties.Any(p => ownershipFKProperties.Contains(p))) + { + dependentEntry.SetEntityState(EntityState.Added); + return; + } + } + } + dependentEntry.SetEntityState(EntityState.Modified); } }