Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/EFCore/ChangeTracking/Internal/NavigationFixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IProperty>();
var ownershipFKProperties = ownership.Properties;
if (keyProperties.Any(p => ownershipFKProperties.Contains(p)))
{
dependentEntry.SetEntityState(EntityState.Added);
return;
}
}
}

dependentEntry.SetEntityState(EntityState.Modified);
}
}
Expand Down
Loading