Skip to content

Commit

Permalink
Delete/detach nested owned entities when replaced by new instances.
Browse files Browse the repository at this point in the history
Fixes #12118
  • Loading branch information
AndriySvyryd committed Mar 14, 2019
1 parent 3e53e94 commit ba7ea2c
Show file tree
Hide file tree
Showing 3 changed files with 704 additions and 95 deletions.
6 changes: 4 additions & 2 deletions src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,8 +1212,7 @@ public virtual void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool for
if (StateManager.SensitiveLoggingEnabled)
{
StateManager.UpdateLogger.CascadeDeleteOrphanSensitive(
this, cascadeFk.PrincipalEntityType,
cascadeState);
this, cascadeFk.PrincipalEntityType, cascadeState);
}
else
{
Expand Down Expand Up @@ -1493,6 +1492,9 @@ public virtual void SetIsLoaded([NotNull] INavigation navigation, bool loaded =
public virtual bool IsLoaded([NotNull] INavigation navigation)
=> _stateData.IsPropertyFlagged(navigation.GetIndex(), PropertyFlag.IsLoaded);

public override string ToString()
=> $"{this.BuildCurrentValuesString(EntityType.FindPrimaryKey().Properties)} {EntityState} {EntityType}";

IUpdateEntry IUpdateEntry.SharedIdentityEntry => SharedIdentityEntry;

private enum CurrentValueType
Expand Down
56 changes: 45 additions & 11 deletions src/EFCore/ChangeTracking/Internal/NavigationFixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,17 @@ var targetDependentEntry
// Propagate principal key values into FKs
foreach (var foreignKey in key.GetReferencingForeignKeys())
{
foreach (var dependentEntry in stateManager
.GetDependentsUsingRelationshipSnapshot(entry, foreignKey).ToList())
{
SetForeignKeyProperties(dependentEntry, entry, foreignKey, setModified: true);
}

if (foreignKey.IsOwnership)
{
continue;
}

// Fix up dependents that have been added by propagating through different foreign key
foreach (var dependentEntry in stateManager.GetDependents(entry, foreignKey).ToList())
{
Expand All @@ -424,11 +435,6 @@ var targetDependentEntry
}
}
}

foreach (var dependentEntry in stateManager.GetDependentsUsingRelationshipSnapshot(entry, foreignKey).ToList())
{
SetForeignKeyProperties(dependentEntry, entry, foreignKey, setModified: true);
}
}
}

Expand Down Expand Up @@ -524,10 +530,21 @@ private void DeleteFixup(InternalEntityEntry entry)
foreach (var foreignKey in entityType.GetReferencingForeignKeys())
{
var dependentToPrincipal = foreignKey.DependentToPrincipal;
if (dependentToPrincipal != null)
if (dependentToPrincipal == null
&& !foreignKey.IsOwnership)
{
continue;
}

var dependentEntries = stateManager.GetDependents(entry, foreignKey);
foreach (var dependentEntry in dependentEntries.ToList())
{
var dependentEntries = stateManager.GetDependents(entry, foreignKey);
foreach (var dependentEntry in dependentEntries)
if (foreignKey.IsOwnership)
{
ConditionallyNullForeignKeyProperties(dependentEntry, entry, foreignKey);
}

if (dependentToPrincipal != null)
{
if (dependentEntry[dependentToPrincipal] == entry.Entity)
{
Expand Down Expand Up @@ -573,9 +590,19 @@ private void InitialFixup(
var dependentEntry = dependents.FirstOrDefault();
if (dependentEntry != null)
{
// Set navigations to and from principal entity that is indicated by FK
SetNavigation(entry, foreignKey.PrincipalToDependent, dependentEntry);
SetNavigation(dependentEntry, foreignKey.DependentToPrincipal, entry);
if (foreignKey.PrincipalToDependent != null
&& entry[foreignKey.PrincipalToDependent] != null
&& entry[foreignKey.PrincipalToDependent] != dependentEntry.Entity)
{
// Clear the dependent FK, since the navigation already points to a different dependent
ConditionallyNullForeignKeyProperties(dependentEntry, entry, foreignKey);
}
else
{
// Set navigations to and from principal entity that is indicated by FK
SetNavigation(entry, foreignKey.PrincipalToDependent, dependentEntry);
SetNavigation(dependentEntry, foreignKey.DependentToPrincipal, entry);
}
}
}
else
Expand Down Expand Up @@ -827,6 +854,13 @@ private void ConditionallyNullForeignKeyProperties(
var dependentProperties = foreignKey.Properties;
var hasOnlyKeyProperties = true;

var currentPrincipal = dependentEntry.StateManager.GetPrincipal(dependentEntry, foreignKey);
if (currentPrincipal != null
&& currentPrincipal != principalEntry)
{
return;
}

if (principalEntry != null
&& principalEntry.EntityState != EntityState.Detached)
{
Expand Down
Loading

0 comments on commit ba7ea2c

Please sign in to comment.