/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual void NavigationCollectionChanged( InternalEntityEntry entry, INavigation navigation, IEnumerable <object> added, IEnumerable <object> removed) { if (_inFixup) { return; } var foreignKey = navigation.ForeignKey; var stateManager = entry.StateManager; var inverse = navigation.FindInverse(); var targetEntityType = navigation.GetTargetType(); foreach (var oldValue in removed) { var oldTargetEntry = stateManager.TryGetEntry(oldValue, targetEntityType); if (oldTargetEntry != null && oldTargetEntry.EntityState != EntityState.Detached) { try { _inFixup = true; // Null FKs and navigations of dependents that have been removed, unless they // have already been changed. ConditionallyNullForeignKeyProperties(oldTargetEntry, entry, foreignKey); if (inverse != null && ReferenceEquals(oldTargetEntry[inverse], entry.Entity) && oldTargetEntry.StateManager.TryGetEntry(oldTargetEntry.Entity, targetEntityType) != null) { SetNavigation(oldTargetEntry, inverse, null); } entry.RemoveFromCollectionSnapshot(navigation, oldValue); } finally { _inFixup = false; } } } foreach (var newValue in added) { var newTargetEntry = targetEntityType.HasDefiningNavigation() ? stateManager.GetOrCreateEntry(newValue, targetEntityType) : stateManager.GetOrCreateEntry(newValue); if (newTargetEntry.EntityState != EntityState.Detached) { try { _inFixup = true; // For a dependent added to the collection, remove it from the collection of // the principal entity that it was previously part of var oldPrincipalEntry = stateManager.GetPrincipalUsingRelationshipSnapshot(newTargetEntry, foreignKey); if (oldPrincipalEntry != null && oldPrincipalEntry != entry) { RemoveFromCollection(oldPrincipalEntry, navigation, newTargetEntry); } // Set the FK properties on added dependents to match this principal SetForeignKeyProperties(newTargetEntry, entry, foreignKey, setModified: true); // Set the inverse navigation to point to this principal SetNavigation(newTargetEntry, inverse, entry); } finally { _inFixup = false; } } else { stateManager.RecordReferencedUntrackedEntity(newValue, navigation, entry); _attacher.AttachGraph(newTargetEntry, EntityState.Added, forceStateWhenUnknownKey: false); } entry.AddToCollectionSnapshot(navigation, newValue); } }
private void DetectNavigationChange(InternalEntityEntry entry, INavigation navigation) { var snapshotValue = entry.GetRelationshipSnapshotValue(navigation); var currentValue = entry[navigation]; var stateManager = entry.StateManager; var added = new HashSet <object>(ReferenceEqualityComparer.Instance); if (navigation.IsCollection()) { var snapshotCollection = (IEnumerable)snapshotValue; var currentCollection = (IEnumerable)currentValue; var removed = new HashSet <object>(ReferenceEqualityComparer.Instance); if (snapshotCollection != null) { foreach (var entity in snapshotCollection) { removed.Add(entity); } } if (currentCollection != null) { foreach (var entity in currentCollection) { if (!removed.Remove(entity)) { added.Add(entity); } } } if (added.Any() || removed.Any()) { stateManager.Notify.NavigationCollectionChanged(entry, navigation, added, removed); foreach (var addedEntity in added) { entry.AddToCollectionSnapshot(navigation, addedEntity); } foreach (var removedEntity in removed) { entry.RemoveFromCollectionSnapshot(navigation, removedEntity); } } } else if (!ReferenceEquals(currentValue, snapshotValue)) { stateManager.Notify.NavigationReferenceChanged(entry, navigation, snapshotValue, currentValue); if (currentValue != null) { added.Add(currentValue); } entry.SetRelationshipSnapshotValue(navigation, currentValue); } foreach (var addedEntity in added) { var addedEntry = stateManager.GetOrCreateEntry(addedEntity); if (addedEntry.EntityState == EntityState.Detached) { _attacher.AttachGraph(addedEntry, EntityState.Added); } } }