public virtual void AttachGraph(InternalEntityEntry rootEntry, EntityState entityState)
     => _graphIterator.TraverseGraph(
         new EntityEntryGraphNode(rootEntry, null)
             {
                 NodeState = entityState
             },
         PaintAction);
        public virtual void Generate(InternalEntityEntry entry)
        {
            foreach (var property in entry.EntityType.GetProperties())
            {
                var isForeignKey = property.IsForeignKey(entry.EntityType);

                if ((property.RequiresValueGenerator || isForeignKey)
                    && property.IsSentinelValue(entry[property]))
                {
                    if (isForeignKey)
                    {
                        _keyPropagator.PropagateValue(entry, property);
                    }
                    else
                    {
                        var valueGenerator = _valueGeneratorSelector.Select(property, entry.EntityType);

                        Debug.Assert(valueGenerator != null);

                        var generatedValue = valueGenerator.NextSkippingSentinel(property);
                        SetGeneratedValue(entry, property, generatedValue, valueGenerator.GeneratesTemporaryValues);
                    }
                }
            }
        }
        public virtual void Generate(InternalEntityEntry entry)
        {
            foreach (var property in entry.EntityType.GetProperties())
            {
                var isForeignKey = property.IsForeignKey(entry.EntityType);

                if ((property.RequiresValueGenerator || isForeignKey)
                    && property.ClrType.IsDefaultValue(entry[property]))
                {
                    if (isForeignKey)
                    {
                        _keyPropagator.PropagateValue(entry, property);
                    }
                    else
                    {
                        var valueGenerator = _valueGeneratorSelector.Select(property, property.IsKey()
                            ? property.DeclaringEntityType
                            : entry.EntityType);

                        Debug.Assert(valueGenerator != null);

                        SetGeneratedValue(entry, property, valueGenerator.Next(), valueGenerator.GeneratesTemporaryValues);
                    }
                }
            }
        }
        private void ForeignKeyPropertyChangedAction(InternalEntityEntry entry, IProperty property, object oldValue, object newValue)
        {
            foreach (var foreignKey in entry.EntityType.GetForeignKeys().Where(p => p.Properties.Contains(property)).Distinct())
            {
                var navigations = _model.GetNavigations(foreignKey).ToList();

                var oldPrincipalEntry = entry.StateManager.GetPrincipal(entry.RelationshipsSnapshot, foreignKey);
                if (oldPrincipalEntry != null)
                {
                    Unfixup(navigations, oldPrincipalEntry, entry);
                }

                var principalEntry = entry.StateManager.GetPrincipal(entry, foreignKey);
                if (principalEntry != null)
                {
                    if (foreignKey.IsUnique)
                    {
                        var oldDependents = entry.StateManager.GetDependents(principalEntry, foreignKey).Where(e => e != entry).ToList();

                        // TODO: Decide how to handle case where multiple values found (negative case)
                        // Issue #739
                        if (oldDependents.Count > 0)
                        {
                            StealReference(foreignKey, oldDependents[0]);
                        }
                    }

                    DoFixup(navigations, principalEntry, new[] { entry });
                }
            }
        }
        /// <summary>
        /// Binds the mixins to the entity through change tracking.
        /// </summary>
        /// <param name="entry">The entity entry.</param>
        /// <param name="entityType">The entity type.</param>
        /// <param name="entity">The entity instance.</param>
        private void BindMixins(InternalEntityEntry entry, IEntityType entityType, object entity)
        {
            var mixinHost = entity as ISupportMixins;
            if (mixinHost != null)
            {
                var mixinTypes = entityType
                    .Annotations
                    .Where(a => a.Name == "MixinType")
                    .Select(a => (Type)a.Value)
                    .Distinct()
                    .ToArray();

                foreach (var mixinType in mixinTypes)
                {
                    // Create the mixin.
                    var mixin = (Mixin)Activator.CreateInstance(mixinType);

                    // Set the resolver.
                    mixin.SetPropertyEntryResolver(p => new PropertyEntry(entry, p));

                    // Assign to the host entity.
                    mixinHost.AddMixin(mixin);
                }
            }
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="PropertyEntry" /> class. Instances of this class
        ///     are returned from methods when using the <see cref="ChangeTracker" /> API and it is not designed
        ///     to be directly constructed in your application code.
        /// </summary>
        /// <param name="internalEntry">  The internal entry tracking information about the entity the property belongs to. </param>
        /// <param name="name"> The name of the property. </param>
        public PropertyEntry([NotNull] InternalEntityEntry internalEntry, [NotNull] string name)
        {
            Check.NotNull(internalEntry, nameof(internalEntry));
            Check.NotEmpty(name, nameof(name));

            _internalEntry = internalEntry;
            Metadata = internalEntry.EntityType.GetProperty(name);
        }
        private static IEnumerable<IPropertyBase> GetProperties(InternalEntityEntry entry)
        {
            var entityType = entry.EntityType;

            return entityType.GetKeys().SelectMany(k => k.Properties)
                .Concat(entityType.GetForeignKeys().SelectMany(fk => fk.Properties))
                .Distinct()
                .Concat<IPropertyBase>(entityType.GetNavigations());
        }
        protected override Sidecar CreateSidecar(InternalEntityEntry entry = null)
        {
            entry = entry ?? CreateInternalEntry();
            var properties = entry.EntityType.GetPrimaryKey().Properties
                .Concat(entry.EntityType.GetForeignKeys().SelectMany(fk => fk.Properties))
                .ToList();

            return new StoreGeneratedValuesFactory().Create(entry, properties);
        }
        public virtual InternalEntityEntry SnapshotAndSubscribe(InternalEntityEntry entry, ValueBuffer? values)
        {
            var entityType = entry.EntityType;

            if (entityType.UseEagerSnapshots())
            {
                if (values != null)
                {
                    entry.OriginalValues = new ValueBufferOriginalValues(entry, values.Value);
                }
                else
                {
                    entry.OriginalValues.TakeSnapshot();
                }

                entry.RelationshipsSnapshot.TakeSnapshot();
            }
            else
            {
                foreach (var navigation in entityType.GetNavigations().Where(n => n.IsNonNotifyingCollection(entry)))
                {
                    entry.RelationshipsSnapshot.TakeSnapshot(navigation);
                }
            }

            var changing = entry.Entity as INotifyPropertyChanging;
            if (changing != null)
            {
                changing.PropertyChanging += (s, e) =>
                    {
                        var property = TryGetPropertyBase(entityType, e.PropertyName);
                        if (property != null)
                        {
                            _notifier.PropertyChanging(entry, property);
                        }
                    };
            }

            var changed = entry.Entity as INotifyPropertyChanged;
            if (changed != null)
            {
                changed.PropertyChanged += (s, e) =>
                    {
                        var property = TryGetPropertyBase(entityType, e.PropertyName);
                        if (property != null)
                        {
                            _notifier.PropertyChanged(entry, property);
                        }
                    };
            }

            return entry;
        }
        private static void SetGeneratedValue(InternalEntityEntry entry, IProperty property, object generatedValue, bool isTemporary)
        {
            if (generatedValue != null)
            {
                entry[property] = generatedValue;

                if (isTemporary)
                {
                    entry.MarkAsTemporary(property);
                }
            }
        }
示例#11
0
        /// <summary>
        ///     <para>
        ///         Initializes a new instance of the <see cref="PropertyEntry" /> class.
        ///     </para>
        ///     <para>
        ///         Instances of this class are returned from methods when using the <see cref="ChangeTracker" /> API and it is
        ///         not designed to be directly constructed in your application code.
        ///     </para>
        /// </summary>
        /// <param name="internalEntry">  The internal entry tracking information about the entity the property belongs to. </param>
        /// <param name="name"> The name of the property. </param>
        public PropertyEntry([NotNull] InternalEntityEntry internalEntry, [NotNull] string name)
        {
            Check.NotNull(internalEntry, nameof(internalEntry));
            Check.NotEmpty(name, nameof(name));

            _internalEntry = internalEntry;
            var property = internalEntry.EntityType.FindProperty(name);
            if (property == null)
            {
                throw new InvalidOperationException(CoreStrings.PropertyNotFound(name, internalEntry.EntityType.DisplayName()));
            }
            Metadata = property;
        }
        private void NavigationReferenceChangedAction(InternalEntityEntry entry, INavigation navigation, object oldValue, object newValue)
        {
            var foreignKey = navigation.ForeignKey;
            var dependentProperties = foreignKey.Properties;
            var principalProperties = foreignKey.PrincipalKey.Properties;

            // TODO: What if the other entry is not yet being tracked?
            // Issue #323
            if (navigation.PointsToPrincipal())
            {
                if (newValue != null)
                {
                    SetForeignKeyValue(foreignKey, entry, entry.StateManager.GetOrCreateEntry(newValue));
                }
                else
                {
                    SetNullForeignKey(entry, dependentProperties);
                }
            }
            else
            {
                Debug.Assert(foreignKey.IsUnique);

                if (newValue != null)
                {
                    var dependentEntry = entry.StateManager.GetOrCreateEntry(newValue);

                    // Avoid eagerly setting FKs (which may be PKs) in un-tracked entities so as not to mess up
                    // Attach behavior that is based on key values.
                    if (dependentEntry.EntityState != EntityState.Detached)
                    {
                        SetForeignKeyValue(foreignKey, dependentEntry, entry);
                    }
                }

                if (oldValue != null)
                {
                    ConditionallySetNullForeignKey(entry.StateManager.GetOrCreateEntry(oldValue), dependentProperties, entry, principalProperties);
                }
            }

            if (oldValue != null)
            {
                ConditionallyClearInverse(entry, navigation, oldValue);
            }

            if (newValue != null)
            {
                SetInverse(entry, navigation, newValue);
            }
        }
        public virtual void PropagateValue(InternalEntityEntry entry, IProperty property)
        {
            Debug.Assert(property.IsForeignKey());

            if (!TryPropagateValue(entry, property)
                && property.IsKey())
            {
                var valueGenerator = TryGetValueGenerator(property);

                if (valueGenerator != null)
                {
                    entry[property] = valueGenerator.Next();
                }
            }
        }
        private bool TryPropagateValue(InternalEntityEntry entry, IProperty property)
        {
            var entityType = property.EntityType;
            var stateManager = entry.StateManager;

            foreach (var foreignKey in entityType.GetForeignKeys())
            {
                for (var propertyIndex = 0; propertyIndex < foreignKey.Properties.Count; propertyIndex++)
                {
                    if (property == foreignKey.Properties[propertyIndex])
                    {
                        object valueToPropagte = null;

                        foreach (var navigation in entityType.GetNavigations()
                            .Concat(foreignKey.PrincipalEntityType.GetNavigations())
                            .Where(n => n.ForeignKey == foreignKey)
                            .Distinct())
                        {
                            var principal = TryFindPrincipal(stateManager, navigation, entry.Entity);

                            if (principal != null)
                            {
                                var principalEntry = stateManager.GetOrCreateEntry(principal);
                                var principalProperty = foreignKey.PrincipalKey.Properties[propertyIndex];

                                var principalValue = principalEntry[principalProperty];
                                if (!principalProperty.IsSentinelValue(principalValue))
                                {
                                    valueToPropagte = principalValue;
                                    break;
                                }
                            }
                        }

                        if (valueToPropagte != null)
                        {
                            entry[property] = valueToPropagte;
                            return true;
                        }
                    }
                }
            }

            return false;
        }
示例#15
0
        public virtual void PropertyChanging(InternalEntityEntry entry, IPropertyBase propertyBase)
        {
            if (!entry.EntityType.UseEagerSnapshots())
            {
                var property = propertyBase as IProperty;
                if (property != null
                    && property.GetOriginalValueIndex() >= 0)
                {
                    entry.OriginalValues.EnsureSnapshot(property);
                }

                var navigation = propertyBase as INavigation;
                if ((navigation != null && !navigation.IsCollection())
                    || (property != null && (property.IsKey() || property.IsForeignKey(entry.EntityType))))
                {
                    // TODO: Consider making snapshot temporary here since it is no longer required after PropertyChanged is called
                    // See issue #730
                    entry.RelationshipsSnapshot.TakeSnapshot(propertyBase);
                }
            }
        }
示例#16
0
        public virtual void PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase)
        {
            var snapshot = entry.TryGetSidecar(Sidecar.WellKnownNames.RelationshipsSnapshot);

            var property = propertyBase as IProperty;
            if (property != null)
            {
                entry.SetPropertyModified(property);

                if (snapshot != null)
                {
                    DetectKeyChange(entry, property, snapshot);
                }
            }
            else
            {
                var navigation = propertyBase as INavigation;
                if (navigation != null
                    && snapshot != null)
                {
                    DetectNavigationChange(entry, navigation, snapshot);
                }
            }
        }
示例#17
0
        private void DetectPropertyChanges(InternalEntityEntry entry)
        {
            var entityType = entry.EntityType;

            if (entityType.HasPropertyChangedNotifications())
            {
                return;
            }

            var snapshot = entry.TryGetSidecar(Sidecar.WellKnownNames.OriginalValues);
            if (snapshot == null)
            {
                return;
            }

            foreach (var property in entityType.GetProperties())
            {
                if (property.GetOriginalValueIndex() >= 0
                    && !Equals(entry[property], snapshot[property]))
                {
                    entry.SetPropertyModified(property);
                }
            }
        }
示例#18
0
 public void PropertyChanging(InternalEntityEntry entry, IPropertyBase property)
 {
 }
示例#19
0
 public void DetectChanges(InternalEntityEntry entry)
 {
 }
示例#20
0
 public void StopTracking(InternalEntityEntry entry)
 {
     throw new NotImplementedException();
 }
示例#21
0
 public InternalEntityEntry StartTracking(InternalEntityEntry entry)
 {
     throw new NotImplementedException();
 }
示例#22
0
            public override void DetectChanges(InternalEntityEntry entry)
            {
                DetectChangesCalled = true;

                base.DetectChanges(entry);
            }
示例#23
0
 public IEnumerable<InternalEntityEntry> GetDependents(InternalEntityEntry principalEntry, IForeignKey foreignKey)
 {
     throw new NotImplementedException();
 }
示例#24
0
 public void UpdateDependentMap(InternalEntityEntry entry, IKeyValue oldKeyValue, IForeignKey foreignKey)
 {
     throw new NotImplementedException();
 }
示例#25
0
 public void UpdateIdentityMap(InternalEntityEntry entry, IKeyValue oldKeyValue, IKey principalKey)
 {
     throw new NotImplementedException();
 }
示例#26
0
 public void UpdateIdentityMap(InternalEntityEntry entry, EntityKey oldKey)
 {
     throw new NotImplementedException();
 }
 protected override Sidecar CreateSidecar(InternalEntityEntry entry = null)
 {
     return new OriginalValuesFactory().Create(entry ?? CreateInternalEntry());
 }
示例#28
0
 protected abstract Sidecar CreateSidecar(InternalEntityEntry entry = null);
示例#29
0
        public virtual IEnumerable<InternalEntityEntry> GetDependents(InternalEntityEntry principalEntry, IForeignKey foreignKey)
        {
            var keyValue = principalEntry.GetPrincipalKeyValue(foreignKey);

            Dictionary<EntityKey, HashSet<InternalEntityEntry>> fkMap;
            HashSet<InternalEntityEntry> dependents;
            return keyValue != EntityKey.InvalidEntityKey
                   && _dependentsMap.TryGetValue(foreignKey, out fkMap)
                   && fkMap.TryGetValue(keyValue, out dependents)
                ? dependents
                : Enumerable.Empty<InternalEntityEntry>();
        }
示例#30
0
        private EntityKey GetKeyValueChecked(IKey key, InternalEntityEntry entry)
        {
            var keyValue = entry.GetPrincipalKeyValue(key);

            if (keyValue == EntityKey.InvalidEntityKey)
            {
                // TODO: Check message text here
                throw new InvalidOperationException(CoreStrings.InvalidPrimaryKey(entry.EntityType.Name));
            }

            return keyValue;
        }