Exemple #1
0
        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);
                }
            }
        }
Exemple #3
0
        /// <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);
                }
            }
        }
Exemple #4
0
        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);
                }
            }
        }
Exemple #6
0
        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));
        }
Exemple #7
0
        /// <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);
                }
            }
        }
Exemple #8
0
        /// <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;
            }
        }