private static void SetForeignKeyProperties( InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, bool setModified, bool fromQuery) { var principalProperties = foreignKey.PrincipalKey.Properties; var dependentProperties = foreignKey.Properties; for (var i = 0; i < foreignKey.Properties.Count; i++) { var principalProperty = principalProperties[i]; var dependentProperty = dependentProperties[i]; var principalValue = principalEntry[principalProperty]; var dependentValue = dependentEntry[dependentProperty]; if (!PrincipalValueEqualsDependentValue(principalProperty, dependentValue, principalValue) || (dependentEntry.IsConceptualNull(dependentProperty) && principalValue != null)) { if (principalEntry.HasTemporaryValue(principalProperty)) { dependentEntry.SetTemporaryValue(dependentProperty, principalValue, setModified); } else { dependentEntry.SetProperty(dependentProperty, principalValue, fromQuery, setModified); } dependentEntry.StateManager.UpdateDependentMap(dependentEntry, foreignKey); dependentEntry.SetRelationshipSnapshotValue(dependentProperty, principalValue); } } }
private static void SetForeignKeyProperties( InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, bool setModified) { var principalProperties = foreignKey.PrincipalKey.Properties; var dependentProperties = foreignKey.Properties; for (var i = 0; i < foreignKey.Properties.Count; i++) { var principalValue = principalEntry[principalProperties[i]]; var dependentProperty = dependentProperties[i]; if (!StructuralComparisons.StructuralEqualityComparer.Equals( dependentEntry[dependentProperty], principalValue) || (dependentEntry.IsConceptualNull(dependentProperty) && principalValue != null)) { dependentEntry.SetProperty(dependentProperty, principalValue, setModified); dependentEntry.StateManager.UpdateDependentMap(dependentEntry, foreignKey); dependentEntry.SetRelationshipSnapshotValue(dependentProperty, principalValue); } } }
/// <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 DetectChanges(InternalEntityEntry entry) { var entityType = entry.EntityType; foreach (var property in entityType.GetProperties()) { if (property.GetOriginalValueIndex() >= 0 && !entry.IsConceptualNull(property) && !Equals(entry[property], entry.GetOriginalValue(property))) { entry.SetPropertyModified(property); } } foreach (var property in entityType.GetProperties()) { DetectKeyChange(entry, property); } if (entry.HasRelationshipSnapshot) { foreach (var navigation in entityType.GetNavigations()) { DetectNavigationChange(entry, navigation); } } }
private void LocalDetectChanges(InternalEntityEntry entry) { var entityType = entry.EntityType; foreach (var property in entityType.GetProperties()) { if (property.GetOriginalValueIndex() >= 0 && !entry.IsModified(property) && !entry.IsConceptualNull(property)) { var current = entry[property]; var original = entry.GetOriginalValue(property); var comparer = property.GetValueComparer(); if (comparer == null) { if (!Equals(current, original)) { SetPropertyModified(); } } else if (!comparer.Equals(current, original)) { SetPropertyModified(); } void SetPropertyModified() { if (entry.EntityState == EntityState.Deleted) { ThrowIfKeyChanged(entry, property); } else { LogChangeDetected(entry, property, original, current); entry.SetPropertyModified(property); } } } } foreach (var property in entityType.GetProperties()) { DetectKeyChange(entry, property); } if (entry.HasRelationshipSnapshot) { foreach (var navigation in entityType.GetNavigations()) { DetectNavigationChange(entry, navigation); } foreach (var navigation in entityType.GetSkipNavigations()) { DetectNavigationChange(entry, navigation); } } }
private void LocalDetectChanges(InternalEntityEntry entry) { var entityType = entry.EntityType; if (entry.EntityType.GetChangeTrackingStrategy() != ChangeTrackingStrategy.Snapshot) { return; } foreach (var property in entityType.GetProperties()) { if (property.GetOriginalValueIndex() >= 0 && !entry.IsModified(property) && !entry.IsConceptualNull(property)) { DetectValueChange(entry, property); } DetectKeyChange(entry, property); } if (entry.HasRelationshipSnapshot) { foreach (var navigation in entityType.GetNavigations()) { DetectNavigationChange(entry, navigation); } foreach (var navigation in entityType.GetSkipNavigations()) { DetectNavigationChange(entry, navigation); } } }
private bool TryCreateFromCurrentValues(InternalEntityEntry entry, out TKey key) { // TODO: Move into delegate foreach (var property in _foreignKey.Properties) { if (entry.IsConceptualNull(property)) { key = default; return(false); } } return(_dependentKeyValueFactory.TryCreateFromCurrentValues(entry, out key)); }
/// <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 DetectChanges(InternalEntityEntry entry) { var entityType = entry.EntityType; foreach (var property in entityType.GetProperties()) { if (property.GetOriginalValueIndex() >= 0 && !entry.IsModified(property) && !entry.IsConceptualNull(property)) { var current = entry[property]; var original = entry.GetOriginalValue(property); var comparer = property.GetValueComparer() ?? property.FindMapping()?.Comparer; if (comparer == null) { if (!Equals(current, original)) { LogChangeDetected(entry, property, original, current); entry.SetPropertyModified(property); } } else { if (!comparer.Equals(current, original)) { LogChangeDetected(entry, property, original, current); entry.SetPropertyModified(property); } } } } foreach (var property in entityType.GetProperties()) { DetectKeyChange(entry, property); } if (entry.HasRelationshipSnapshot) { foreach (var navigation in entityType.GetNavigations()) { DetectNavigationChange(entry, navigation); } } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual void KeyPropertyChanged( InternalEntityEntry entry, IProperty property, IReadOnlyList <IKey> containingPrincipalKeys, IReadOnlyList <IForeignKey> containingForeignKeys, object oldValue, object newValue) { if (entry.EntityState == EntityState.Detached) { return; } try { _inFixup = true; var stateManager = entry.StateManager; foreach (var foreignKey in containingForeignKeys) { var newPrincipalEntry = stateManager.FindPrincipal(entry, foreignKey) ?? stateManager.FindPrincipalUsingPreStoreGeneratedValues(entry, foreignKey); var oldPrincipalEntry = stateManager.FindPrincipalUsingRelationshipSnapshot(entry, foreignKey); var principalToDependent = foreignKey.PrincipalToDependent; if (principalToDependent != null) { if (oldPrincipalEntry != null && oldPrincipalEntry.EntityState != EntityState.Deleted) { // Remove this entity from the principal collection that it was previously part of, // or null the navigation for a 1:1 unless that reference was already changed. ResetReferenceOrRemoveCollection(oldPrincipalEntry, principalToDependent, entry, fromQuery: false); } if (newPrincipalEntry != null && !entry.IsConceptualNull(property)) { // Add this entity to the collection of the new principal, or set the navigation for a 1:1 SetReferenceOrAddToCollection(newPrincipalEntry, principalToDependent, entry, fromQuery: false); } } var dependentToPrincipal = foreignKey.DependentToPrincipal; if (dependentToPrincipal != null) { if (newPrincipalEntry != null) { if (foreignKey.IsUnique) { // Dependent has been changed to point to a new principal. // Find the dependent that previously pointed to the new principal and null out its FKs // and navigation property. A.k.a. reference stealing. // However, if the FK has already been changed or the reference is already set to point // to something else, then don't change it. var targetDependentEntry = stateManager.GetDependentsUsingRelationshipSnapshot(newPrincipalEntry, foreignKey).FirstOrDefault(); if (targetDependentEntry != null && targetDependentEntry != entry) { ConditionallyNullForeignKeyProperties(targetDependentEntry, newPrincipalEntry, foreignKey); if (ReferenceEquals(targetDependentEntry[dependentToPrincipal], newPrincipalEntry.Entity) && targetDependentEntry.StateManager.TryGetEntry( targetDependentEntry.Entity, foreignKey.DeclaringEntityType) != null) { SetNavigation(targetDependentEntry, dependentToPrincipal, null, fromQuery: false); } } } if (!entry.IsConceptualNull(property)) { SetNavigation(entry, dependentToPrincipal, newPrincipalEntry, fromQuery: false); } } else if (oldPrincipalEntry != null) { if (ReferenceEquals(entry[dependentToPrincipal], oldPrincipalEntry.Entity) && entry.StateManager.TryGetEntry(entry.Entity, foreignKey.DeclaringEntityType) != null) { SetNavigation(entry, dependentToPrincipal, null, fromQuery: false); } } else { if (entry[dependentToPrincipal] == null && entry.StateManager.TryGetEntry(entry.Entity, foreignKey.DeclaringEntityType) != null) { // FK has changed but navigation is still null entry.SetIsLoaded(dependentToPrincipal, false); } } } stateManager.UpdateDependentMap(entry, foreignKey); } foreach (var key in containingPrincipalKeys) { stateManager.UpdateIdentityMap(entry, key); // 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, fromQuery: false); } 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()) { var principalToDependent = foreignKey.PrincipalToDependent; if (principalToDependent != null) { if (!entry.IsConceptualNull(property)) { // Add this entity to the collection of the new principal, or set the navigation for a 1:1 SetReferenceOrAddToCollection(entry, principalToDependent, dependentEntry, fromQuery: false); } } var dependentToPrincipal = foreignKey.DependentToPrincipal; if (dependentToPrincipal != null) { if (!entry.IsConceptualNull(property)) { SetNavigation(dependentEntry, dependentToPrincipal, entry, fromQuery: false); } } } } } entry.SetRelationshipSnapshotValue(property, newValue); } finally { _inFixup = false; } }