Пример #1
0
        internal void UpdateForeignKeyValues(IEntityWrapper dependentEntity, EntityKey principalKey)
        {
            ReferentialConstraint referentialConstraint = ((AssociationType)this.RelationMetadata).ReferentialConstraints[0];
            ObjectStateManager    objectStateManager    = this.ObjectContext.ObjectStateManager;

            objectStateManager.TransactionManager.BeginForeignKeyUpdate(this);
            try
            {
                EntitySet entitySet = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.FromEndMember.Name].EntitySet;
                StateManagerTypeMetadata managerTypeMetadata = objectStateManager.GetOrAddStateManagerTypeMetadata(dependentEntity.IdentityType, entitySet);
                for (int index = 0; index < referentialConstraint.FromProperties.Count; ++index)
                {
                    object valueByName      = principalKey.FindValueByName(referentialConstraint.FromProperties[index].Name);
                    int    olayerMemberName = managerTypeMetadata.GetOrdinalforOLayerMemberName(referentialConstraint.ToProperties[index].Name);
                    object x = managerTypeMetadata.Member(olayerMemberName).GetValue(dependentEntity.Entity);
                    if (!ByValueEqualityComparer.Default.Equals(x, valueByName))
                    {
                        dependentEntity.SetCurrentValue(dependentEntity.ObjectStateEntry, managerTypeMetadata.Member(olayerMemberName), -1, dependentEntity.Entity, valueByName);
                    }
                }
                this.SetCachedForeignKey(principalKey, dependentEntity.ObjectStateEntry);
                if (this.WrappedOwner.ObjectStateEntry == null)
                {
                    return;
                }
                objectStateManager.ForgetEntryWithConceptualNull(this.WrappedOwner.ObjectStateEntry, false);
            }
            finally
            {
                objectStateManager.TransactionManager.EndForeignKeyUpdate();
            }
        }
Пример #2
0
        /// <summary>
        /// Takes key values from the given principal key and transfers them to the foreign key properties
        /// of the dependant entry.  This method requires a context, but does not require that either
        /// entity or key is in the context.  This allows it to work in NoTracking cases where we have the context
        /// but we're not tracked by that context.
        /// </summary>
        /// <param name="dependentEntity">The entity into which foreign key values will be written</param>
        /// <param name="principalEntity">The key from which key values will be obtained</param>
        internal void UpdateForeignKeyValues(IEntityWrapper dependentEntity, EntityKey principalKey)
        {
            Debug.Assert(dependentEntity.Entity != null, "dependentEntity.Entity == null");
            Debug.Assert(principalKey != null, "principalKey == null");
            Debug.Assert(!principalKey.IsTemporary, "Cannot update from a temp key");
            Debug.Assert(this.IsForeignKey, "cannot update foreign key values if the relationship is not a FK");
            ReferentialConstraint constraint = ((AssociationType)this.RelationMetadata).ReferentialConstraints[0];

            Debug.Assert(constraint != null, "null constraint");

            ObjectStateManager stateManager = ObjectContext.ObjectStateManager;

            stateManager.TransactionManager.BeginForeignKeyUpdate(this);
            try
            {
                EntitySet dependentEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndProperty.Name].EntitySet;
                StateManagerTypeMetadata dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(dependentEntity.IdentityType, dependentEntitySet);

                for (int i = 0; i < constraint.FromProperties.Count; i++)
                {
                    object value            = principalKey.FindValueByName(constraint.FromProperties[i].Name);
                    int    dependentOrdinal = dependentTypeMetadata.GetOrdinalforOLayerMemberName(constraint.ToProperties[i].Name);
                    object currentValue     = dependentTypeMetadata.Member(dependentOrdinal).GetValue(dependentEntity.Entity);
                    if (!ByValueEqualityComparer.Default.Equals(currentValue, value))
                    {
                        dependentEntity.SetCurrentValue(
                            dependentEntity.ObjectStateEntry,
                            dependentTypeMetadata.Member(dependentOrdinal),
                            -1,
                            dependentEntity.Entity,
                            value);
                    }
                }

                SetCachedForeignKey(principalKey, dependentEntity.ObjectStateEntry);
                if (WrappedOwner.ObjectStateEntry != null)
                {
                    stateManager.ForgetEntryWithConceptualNull(WrappedOwner.ObjectStateEntry, resetAllKeys: false);
                }
            }
            finally
            {
                stateManager.TransactionManager.EndForeignKeyUpdate();
            }
        }
Пример #3
0
        /// <summary>
        /// Attempts to null all FKs associated with the dependent end of this relationship on this entity.
        /// This may result in setting conceptual nulls if the FK is not nullable.
        /// </summary>
        internal void NullAllForeignKeys()
        {
            Debug.Assert(ObjectContext != null, "Nulling FKs only works when attached.");
            Debug.Assert(IsForeignKey, "Cannot null FKs for independent associations.");

            ObjectStateManager stateManager = ObjectContext.ObjectStateManager;
            EntityEntry        entry        = WrappedOwner.ObjectStateEntry;
            TransactionManager transManager = stateManager.TransactionManager;

            if (!transManager.IsGraphUpdate && !transManager.IsAttachTracking && !transManager.IsRelatedEndAdd)
            {
                ReferentialConstraint constraint = ((AssociationType)RelationMetadata).ReferentialConstraints.Single();
                if (TargetRoleName == constraint.FromRole.Name) // Only do this on the dependent end
                {
                    if (transManager.IsDetaching)
                    {
                        // If the principal is being detached, then the dependent must be added back to the
                        // dangling keys index.
                        // Perf note: The dependent currently gets added when it is being detached and is then
                        // removed again later in the process.  The code could be optimized to prevent this.
                        Debug.Assert(entry != null, "State entry must exist while detaching.");
                        EntityKey foreignKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                        if (foreignKey != null)
                        {
                            stateManager.AddEntryContainingForeignKeyToIndex(foreignKey, entry);
                        }
                    }
                    else if (!ReferenceEquals(stateManager.EntityInvokingFKSetter, WrappedOwner.Entity) && !transManager.IsForeignKeyUpdate)
                    {
                        transManager.BeginForeignKeyUpdate(this);
                        try
                        {
                            bool      unableToNull        = true;
                            bool      canSetModifiedProps = entry != null && (entry.State == EntityState.Modified || entry.State == EntityState.Unchanged);
                            EntitySet dependentEntitySet  = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndProperty.Name].EntitySet;
                            StateManagerTypeMetadata dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(WrappedOwner.IdentityType, dependentEntitySet);

                            for (int i = 0; i < constraint.FromProperties.Count; i++)
                            {
                                string propertyName               = constraint.ToProperties[i].Name;
                                int    dependentOrdinal           = dependentTypeMetadata.GetOrdinalforOLayerMemberName(propertyName);
                                StateManagerMemberMetadata member = dependentTypeMetadata.Member(dependentOrdinal);

                                // This is a check for nullability in o-space. However, o-space nullability is not the
                                // same as nullability of the underlying type. In particular, one difference is that when
                                // attribute-based mapping is used then a property can be marked as not nullable in o-space
                                // even when the underlying CLR type is nullable. For such a case, we treat the property
                                // as if it were not nullable (since that's what we have shipped) even though we could
                                // technically set it to null.
                                if (member.ClrMetadata.Nullable)
                                {
                                    // Only set the value to null if it is not already null.
                                    if (member.GetValue(WrappedOwner.Entity) != null)
                                    {
                                        WrappedOwner.SetCurrentValue(
                                            WrappedOwner.ObjectStateEntry,
                                            dependentTypeMetadata.Member(dependentOrdinal),
                                            -1,
                                            WrappedOwner.Entity,
                                            null);
                                    }
                                    else
                                    {
                                        // Given that the current value is null, this next check confirms that the original
                                        // value is also null.  If it isn't, then we must make sure that the entity is marked
                                        // as modified.
                                        // This case can happen because fixup in the entity can set the FK to null while processing
                                        // a RelatedEnd operation.  This will be detected by DetectChanges, but when performing
                                        // RelatedEnd operations the user is not required to call DetectChanges.
                                        if (canSetModifiedProps && WrappedOwner.ObjectStateEntry.OriginalValues.GetValue(dependentOrdinal) != null)
                                        {
                                            entry.SetModifiedProperty(propertyName);
                                        }
                                    }
                                    unableToNull = false;
                                }
                                else if (canSetModifiedProps)
                                {
                                    entry.SetModifiedProperty(propertyName);
                                }
                            }
                            if (unableToNull)
                            {
                                // We were unable to null out the FK because all FK properties were non-nullable.
                                // We need to keep track of this state so that we treat the FK as null even though
                                // we were not able to null it.  This prevents the FK from being used for fixup and
                                // also causes an exception to be thrown if an attempt is made to commit in this state.

                                //We should only set a conceptual null if the entity is tracked
                                if (entry != null)
                                {
                                    //The CachedForeignKey may be null if we are putting
                                    //back a Conceptual Null as part of roll back
                                    EntityKey realKey = CachedForeignKey;
                                    if (realKey == null)
                                    {
                                        realKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                                    }

                                    // Note that the realKey can still be null here for a situation where the key is marked not nullable
                                    // in o-space and yet the underlying type is nullable and the entity has been added or attached with a null
                                    // value for the property. This will cause SaveChanges to throw unless the entity is marked
                                    // as deleted before SaveChanges is called, in which case we don't want to set a conceptual
                                    // null here as the call might very well succeed in the database since, unless the FK is
                                    // a concurrency token, the value we have for it is not used at all for the delete.
                                    if (realKey != null)
                                    {
                                        SetCachedForeignKey(ForeignKeyFactory.CreateConceptualNullKey(realKey), entry);
                                        stateManager.RememberEntryWithConceptualNull(entry);
                                    }
                                }
                            }
                            else
                            {
                                SetCachedForeignKey(null, entry);
                            }
                        }
                        finally
                        {
                            transManager.EndForeignKeyUpdate();
                        }
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Takes key values from the given principal entity and transfers them to the foreign key properties
        /// of the dependant entry.  This method requires a context, but does not require that either
        /// entity is in the context.  This allows it to work in NoTracking cases where we have the context
        /// but we're not tracked by that context.
        /// </summary>
        /// <param name="dependentEntity">The entity into which foreign key values will be written</param>
        /// <param name="principalEntity">The entity from which key values will be obtained</param>
        /// <param name="changedFKs">If non-null, then keeps track of FKs that have already been set such that an exception can be thrown if we find conflicting values</param>
        /// <param name="forceChange">If true, then the property setter is called even if FK values already match,
        ///                           which causes the FK properties to be marked as modified.</param>
        internal void UpdateForeignKeyValues(IEntityWrapper dependentEntity, IEntityWrapper principalEntity, Dictionary <int, object> changedFKs, bool forceChange)
        {
            Debug.Assert(dependentEntity.Entity != null, "dependentEntity.Entity == null");
            Debug.Assert(principalEntity.Entity != null, "principalEntity.Entity == null");
            Debug.Assert(this.IsForeignKey, "cannot update foreign key values if the relationship is not a FK");
            ReferentialConstraint constraint = ((AssociationType)this.RelationMetadata).ReferentialConstraints[0];

            Debug.Assert(constraint != null, "null constraint");

            bool isUnchangedDependent = (object)WrappedOwner.EntityKey != null &&
                                        !WrappedOwner.EntityKey.IsTemporary &&
                                        IsDependentEndOfReferentialConstraint(checkIdentifying: true);

            ObjectStateManager stateManager = ObjectContext.ObjectStateManager;

            stateManager.TransactionManager.BeginForeignKeyUpdate(this);
            try
            {
                EntitySet principalEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[ToEndMember.Name].EntitySet;
                StateManagerTypeMetadata principalTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(principalEntity.IdentityType, principalEntitySet);

                EntitySet dependentEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndProperty.Name].EntitySet;
                StateManagerTypeMetadata dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(dependentEntity.IdentityType, dependentEntitySet);

                var      principalProps = constraint.FromProperties;
                int      numValues      = principalProps.Count;
                string[] keyNames       = null;
                object[] values         = null;
                if (numValues > 1)
                {
                    keyNames = principalEntitySet.ElementType.KeyMemberNames;
                    values   = new object[numValues];
                }
                for (int i = 0; i < numValues; i++)
                {
                    int    principalOrdinal = principalTypeMetadata.GetOrdinalforOLayerMemberName(principalProps[i].Name);
                    object value            = principalTypeMetadata.Member(principalOrdinal).GetValue(principalEntity.Entity);
                    int    dependentOrdinal = dependentTypeMetadata.GetOrdinalforOLayerMemberName(constraint.ToProperties[i].Name);
                    bool   valueChanging    = !ByValueEqualityComparer.Default.Equals(dependentTypeMetadata.Member(dependentOrdinal).GetValue(dependentEntity.Entity), value);
                    if (forceChange || valueChanging)
                    {
                        if (isUnchangedDependent)
                        {
                            ValidateSettingRIConstraints(principalEntity, settingToNull: value == null, changingForeignKeyValue: valueChanging);
                        }
                        // If we're tracking FK values that have already been set, then compare the value we are about to set
                        // to the value we previously set for this ordinal, if such a value exists.  If they don't match then
                        // it means that we got conflicting FK values from two different PKs and we should throw.
                        if (changedFKs != null)
                        {
                            object previouslySetValue;
                            if (changedFKs.TryGetValue(dependentOrdinal, out previouslySetValue))
                            {
                                if (!ByValueEqualityComparer.Default.Equals(previouslySetValue, value))
                                {
                                    throw new InvalidOperationException(System.Data.Entity.Strings.Update_ReferentialConstraintIntegrityViolation);
                                }
                            }
                            else
                            {
                                changedFKs[dependentOrdinal] = value;
                            }
                        }
                        dependentEntity.SetCurrentValue(
                            dependentEntity.ObjectStateEntry,
                            dependentTypeMetadata.Member(dependentOrdinal),
                            -1,
                            dependentEntity.Entity,
                            value);
                    }

                    if (numValues > 1)
                    {
                        int keyIndex = Array.IndexOf(keyNames, principalProps[i].Name);
                        Debug.Assert(keyIndex >= 0 && keyIndex < numValues, "Could not find constraint prop name in entity set key names");
                        values[keyIndex] = value;
                    }
                    else
                    {
                        SetCachedForeignKey(new EntityKey(principalEntitySet, value), dependentEntity.ObjectStateEntry);
                    }
                }

                if (numValues > 1)
                {
                    SetCachedForeignKey(new EntityKey(principalEntitySet, values), dependentEntity.ObjectStateEntry);
                }
                if (WrappedOwner.ObjectStateEntry != null)
                {
                    stateManager.ForgetEntryWithConceptualNull(WrappedOwner.ObjectStateEntry, resetAllKeys: false);
                }
            }
            finally
            {
                stateManager.TransactionManager.EndForeignKeyUpdate();
            }
        }
Пример #5
0
        internal void NullAllForeignKeys()
        {
            ObjectStateManager objectStateManager = this.ObjectContext.ObjectStateManager;
            EntityEntry        objectStateEntry   = this.WrappedOwner.ObjectStateEntry;
            TransactionManager transactionManager = objectStateManager.TransactionManager;

            if (transactionManager.IsGraphUpdate || transactionManager.IsAttachTracking || transactionManager.IsRelatedEndAdd)
            {
                return;
            }
            ReferentialConstraint referentialConstraint = ((AssociationType)this.RelationMetadata).ReferentialConstraints.Single <ReferentialConstraint>();

            if (!(this.TargetRoleName == referentialConstraint.FromRole.Name))
            {
                return;
            }
            if (transactionManager.IsDetaching)
            {
                EntityKey foreignKeyValues = ForeignKeyFactory.CreateKeyFromForeignKeyValues(objectStateEntry, (RelatedEnd)this);
                if (!(foreignKeyValues != (EntityKey)null))
                {
                    return;
                }
                objectStateManager.AddEntryContainingForeignKeyToIndex(this, foreignKeyValues, objectStateEntry);
            }
            else
            {
                if (object.ReferenceEquals(objectStateManager.EntityInvokingFKSetter, this.WrappedOwner.Entity) || transactionManager.IsForeignKeyUpdate)
                {
                    return;
                }
                transactionManager.BeginForeignKeyUpdate(this);
                try
                {
                    bool      flag1     = true;
                    bool      flag2     = objectStateEntry != null && (objectStateEntry.State == EntityState.Modified || objectStateEntry.State == EntityState.Unchanged);
                    EntitySet entitySet = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.FromEndMember.Name].EntitySet;
                    StateManagerTypeMetadata managerTypeMetadata = objectStateManager.GetOrAddStateManagerTypeMetadata(this.WrappedOwner.IdentityType, entitySet);
                    for (int index = 0; index < referentialConstraint.FromProperties.Count; ++index)
                    {
                        string name             = referentialConstraint.ToProperties[index].Name;
                        int    olayerMemberName = managerTypeMetadata.GetOrdinalforOLayerMemberName(name);
                        StateManagerMemberMetadata managerMemberMetadata = managerTypeMetadata.Member(olayerMemberName);
                        if (managerMemberMetadata.ClrMetadata.Nullable)
                        {
                            if (managerMemberMetadata.GetValue(this.WrappedOwner.Entity) != null)
                            {
                                this.WrappedOwner.SetCurrentValue(this.WrappedOwner.ObjectStateEntry, managerTypeMetadata.Member(olayerMemberName), -1, this.WrappedOwner.Entity, (object)null);
                            }
                            else if (flag2 && this.WrappedOwner.ObjectStateEntry.OriginalValues.GetValue(olayerMemberName) != null)
                            {
                                objectStateEntry.SetModifiedProperty(name);
                            }
                            flag1 = false;
                        }
                        else if (flag2)
                        {
                            objectStateEntry.SetModifiedProperty(name);
                        }
                    }
                    if (flag1)
                    {
                        if (objectStateEntry == null)
                        {
                            return;
                        }
                        EntityKey originalKey = this.CachedForeignKey;
                        if (originalKey == (EntityKey)null)
                        {
                            originalKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(objectStateEntry, (RelatedEnd)this);
                        }
                        if (!(originalKey != (EntityKey)null))
                        {
                            return;
                        }
                        this.SetCachedForeignKey(ForeignKeyFactory.CreateConceptualNullKey(originalKey), objectStateEntry);
                        objectStateManager.RememberEntryWithConceptualNull(objectStateEntry);
                    }
                    else
                    {
                        this.SetCachedForeignKey((EntityKey)null, objectStateEntry);
                    }
                }
                finally
                {
                    transactionManager.EndForeignKeyUpdate();
                }
            }
        }
Пример #6
0
        internal void UpdateForeignKeyValues(
            IEntityWrapper dependentEntity,
            IEntityWrapper principalEntity,
            Dictionary <int, object> changedFKs,
            bool forceChange)
        {
            ReferentialConstraint referentialConstraint = ((AssociationType)this.RelationMetadata).ReferentialConstraints[0];
            bool flag = (object)this.WrappedOwner.EntityKey != null && !this.WrappedOwner.EntityKey.IsTemporary && this.IsDependentEndOfReferentialConstraint(true);
            ObjectStateManager objectStateManager = this.ObjectContext.ObjectStateManager;

            objectStateManager.TransactionManager.BeginForeignKeyUpdate(this);
            try
            {
                EntitySet entitySet1 = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.ToEndMember.Name].EntitySet;
                StateManagerTypeMetadata managerTypeMetadata1 = objectStateManager.GetOrAddStateManagerTypeMetadata(principalEntity.IdentityType, entitySet1);
                EntitySet entitySet2 = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.FromEndMember.Name].EntitySet;
                StateManagerTypeMetadata managerTypeMetadata2           = objectStateManager.GetOrAddStateManagerTypeMetadata(dependentEntity.IdentityType, entitySet2);
                ReadOnlyMetadataCollection <EdmProperty> fromProperties = referentialConstraint.FromProperties;
                int      count = fromProperties.Count;
                string[] array = (string[])null;
                object[] compositeKeyValues = (object[])null;
                if (count > 1)
                {
                    array = entitySet1.ElementType.KeyMemberNames;
                    compositeKeyValues = new object[count];
                }
                for (int index1 = 0; index1 < count; ++index1)
                {
                    int    olayerMemberName1 = managerTypeMetadata1.GetOrdinalforOLayerMemberName(fromProperties[index1].Name);
                    object obj = managerTypeMetadata1.Member(olayerMemberName1).GetValue(principalEntity.Entity);
                    int    olayerMemberName2       = managerTypeMetadata2.GetOrdinalforOLayerMemberName(referentialConstraint.ToProperties[index1].Name);
                    bool   changingForeignKeyValue = !ByValueEqualityComparer.Default.Equals(managerTypeMetadata2.Member(olayerMemberName2).GetValue(dependentEntity.Entity), obj);
                    if (forceChange || changingForeignKeyValue)
                    {
                        if (flag)
                        {
                            this.ValidateSettingRIConstraints(principalEntity, obj == null, changingForeignKeyValue);
                        }
                        if (changedFKs != null)
                        {
                            object x;
                            if (changedFKs.TryGetValue(olayerMemberName2, out x))
                            {
                                if (!ByValueEqualityComparer.Default.Equals(x, obj))
                                {
                                    throw new InvalidOperationException(Strings.Update_ReferentialConstraintIntegrityViolation);
                                }
                            }
                            else
                            {
                                changedFKs[olayerMemberName2] = obj;
                            }
                        }
                        dependentEntity.SetCurrentValue(dependentEntity.ObjectStateEntry, managerTypeMetadata2.Member(olayerMemberName2), -1, dependentEntity.Entity, obj);
                    }
                    if (count > 1)
                    {
                        int index2 = Array.IndexOf <string>(array, fromProperties[index1].Name);
                        compositeKeyValues[index2] = obj;
                    }
                    else
                    {
                        this.SetCachedForeignKey(obj == null ? (EntityKey)null : new EntityKey((EntitySetBase)entitySet1, obj), dependentEntity.ObjectStateEntry);
                    }
                }
                if (count > 1)
                {
                    this.SetCachedForeignKey(((IEnumerable <object>)compositeKeyValues).Any <object>((Func <object, bool>)(v => v == null)) ? (EntityKey)null : new EntityKey((EntitySetBase)entitySet1, compositeKeyValues), dependentEntity.ObjectStateEntry);
                }
                if (this.WrappedOwner.ObjectStateEntry == null)
                {
                    return;
                }
                objectStateManager.ForgetEntryWithConceptualNull(this.WrappedOwner.ObjectStateEntry, false);
            }
            finally
            {
                objectStateManager.TransactionManager.EndForeignKeyUpdate();
            }
        }