private void DetectKeyChange(InternalEntityEntry entry, IProperty property, Sidecar snapshot) { if (!snapshot.HasValue(property)) { return; } var keys = property.FindContainingKeys().ToList(); var foreignKeys = property.FindContainingForeignKeys(entry.EntityType).ToList(); if (keys.Count > 0 || foreignKeys.Count > 0) { var snapshotValue = snapshot[property]; var currentValue = entry[property]; // Note that mutation of a byte[] key is not supported or detected, but two different instances // of byte[] with the same content must be detected as equal. if (!StructuralComparisons.StructuralEqualityComparer.Equals(currentValue, snapshotValue)) { var stateManager = entry.StateManager; if (foreignKeys.Count > 0) { stateManager.Notify.ForeignKeyPropertyChanged(entry, property, snapshotValue, currentValue); foreach (var foreignKey in foreignKeys) { stateManager.UpdateDependentMap(entry, snapshot.GetDependentKeyValue(foreignKey), foreignKey); } } if (keys.Count > 0) { foreach (var key in keys) { stateManager.UpdateIdentityMap(entry, snapshot.GetPrincipalKeyValue(key), key); } stateManager.Notify.PrincipalKeyPropertyChanged(entry, property, snapshotValue, currentValue); } snapshot.TakeSnapshot(property); } } }
public virtual void SetPropertyModified([NotNull] IProperty property, bool isModified = true) { // TODO: Restore original value to reject changes when isModified is false // Issue #742 var currentState = _stateData.EntityState; if (currentState == EntityState.Added || currentState == EntityState.Detached) { MarkAsTemporary(property, isTemporary: false); OriginalValues.TakeSnapshot(property); } if ((currentState != EntityState.Modified && currentState != EntityState.Unchanged) // TODO: Consider allowing computed properties to be forcibly marked as modified // Issue #711 || property.IsStoreComputed) { return; } if (isModified && property.IsReadOnly) { throw new NotSupportedException(Strings.PropertyReadOnly(property.Name, EntityType.Name)); } _stateData.FlagProperty(property.Index, isModified); // Don't change entity state if it is Added or Deleted if (isModified && currentState == EntityState.Unchanged) { StateManager.Notify.StateChanging(this, EntityState.Modified); _stateData.EntityState = EntityState.Modified; StateManager.Notify.StateChanged(this, currentState); } else if (!isModified && !_stateData.AnyPropertiesFlagged()) { StateManager.Notify.StateChanging(this, EntityState.Unchanged); _stateData.EntityState = EntityState.Unchanged; StateManager.Notify.StateChanged(this, currentState); } }
private void DetectKeyChange(InternalEntityEntry entry, IProperty property, Sidecar snapshot) { if (!snapshot.HasValue(property)) { return; } // TODO: Perf: make it fast to check if a property is part of any key var isPrimaryKey = property.IsPrimaryKey(); var isPrincipalKey = _model.GetReferencingForeignKeys(property).Any(); var isForeignKey = property.IsForeignKey(); if (isPrimaryKey || isPrincipalKey || isForeignKey) { var snapshotValue = snapshot[property]; var currentValue = entry[property]; // Note that mutation of a byte[] key is not supported or detected, but two different instances // of byte[] with the same content must be detected as equal. if (!StructuralComparisons.StructuralEqualityComparer.Equals(currentValue, snapshotValue)) { if (isForeignKey) { entry.StateManager.Notify.ForeignKeyPropertyChanged(entry, property, snapshotValue, currentValue); } if (isPrimaryKey) { entry.StateManager.UpdateIdentityMap(entry, snapshot.GetPrimaryKeyValue()); } if (isPrincipalKey) { entry.StateManager.Notify.PrincipalKeyPropertyChanged(entry, property, snapshotValue, currentValue); } snapshot.TakeSnapshot(property); } } }
public virtual void SetPropertyModified([NotNull] IProperty property, bool isModified = true) { // TODO: Restore original value to reject changes when isModified is false // Issue #742 var currentState = _stateData.EntityState; if (currentState == EntityState.Added || currentState == EntityState.Detached) { MarkAsTemporary(property, isTemporary: false); OriginalValues.TakeSnapshot(property); } if (currentState != EntityState.Modified && currentState != EntityState.Unchanged) { return; } if (isModified && property.IsKey()) { throw new NotSupportedException(CoreStrings.KeyReadOnly(property.Name, EntityType.DisplayName())); } _stateData.FlagProperty(property.Index, PropertyFlag.TemporaryOrModified, isModified); // Don't change entity state if it is Added or Deleted if (isModified && currentState == EntityState.Unchanged) { StateManager.Notify.StateChanging(this, EntityState.Modified); _stateData.EntityState = EntityState.Modified; StateManager.Notify.StateChanged(this, currentState); } else if (!isModified && !_stateData.AnyPropertiesFlagged(PropertyFlag.TemporaryOrModified)) { StateManager.Notify.StateChanging(this, EntityState.Unchanged); _stateData.EntityState = EntityState.Unchanged; StateManager.Notify.StateChanged(this, currentState); } }
private void DetectNavigationChange(InternalEntityEntry entry, INavigation navigation, Sidecar snapshot) { var snapshotValue = snapshot[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); snapshot.TakeSnapshot(navigation); } } else if (!ReferenceEquals(currentValue, snapshotValue)) { stateManager.Notify.NavigationReferenceChanged(entry, navigation, snapshotValue, currentValue); if (currentValue != null) { added.Add(currentValue); } snapshot.TakeSnapshot(navigation); } foreach (var addedEntity in added) { var addedEntry = stateManager.GetOrCreateEntry(addedEntity); if (addedEntry.EntityState == EntityState.Detached) { _attacher.AttachGraph(addedEntry, EntityState.Added); } } }
private void DetectNavigationChange(InternalEntityEntry entry, INavigation navigation, Sidecar snapshot) { var snapshotValue = snapshot[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); snapshot.TakeSnapshot(navigation); } } else if (!ReferenceEquals(currentValue, snapshotValue)) { stateManager.Notify.NavigationReferenceChanged(entry, navigation, snapshotValue, currentValue); if (currentValue != null) { added.Add(currentValue); } snapshot.TakeSnapshot(navigation); } foreach (var addedEntity in added) { var addedEntry = stateManager.GetOrCreateEntry(addedEntity); if (addedEntry.EntityState == EntityState.Detached) { _attacher.AttachGraph(addedEntry, EntityState.Added); } } }