src/Shared/EntityFramework/Core/Objects/DataClasses/EntityReference.cs
// <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>
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.
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 .
internal void UpdateForeignKeyValues(
            IEntityWrapper dependentEntity, IEntityWrapper principalEntity, Dictionary<int, object> changedFKs, bool forceChange)
        {
            DebugCheck.NotNull(dependentEntity.Entity);
            DebugCheck.NotNull(principalEntity.Entity);
            Debug.Assert(IsForeignKey, "cannot update foreign key values if the relationship is not a FK");
            var constraint = ((AssociationType)RelationMetadata).ReferentialConstraints[0];
            Debug.Assert(constraint != null, "null constraint");
            var isUnchangedDependent = (object)WrappedOwner.EntityKey != null &&
                                       !WrappedOwner.EntityKey.IsTemporary &&
                                       IsDependentEndOfReferentialConstraint(checkIdentifying: true);
            var stateManager = ObjectContext.ObjectStateManager;
            stateManager.TransactionManager.BeginForeignKeyUpdate(this);
            try
            {
                var principalEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[ToEndMember.Name].EntitySet;
                var principalTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(principalEntity.IdentityType, principalEntitySet);
                var dependentEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndMember.Name].EntitySet;
                var dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(dependentEntity.IdentityType, dependentEntitySet);
                var principalProps = constraint.FromProperties;
                var numValues = principalProps.Count;
                string[] keyNames = null;
                object[] values = null;
                if (numValues > 1)
                {
                    keyNames = principalEntitySet.ElementType.KeyMemberNames;
                    values = new object[numValues];
                }
                for (var i = 0; i < numValues; i++)
                {
                    var principalOrdinal = principalTypeMetadata.GetOrdinalforOLayerMemberName(principalProps[i].Name);
                    var value = principalTypeMetadata.Member(principalOrdinal).GetValue(principalEntity.Entity);
                    var dependentOrdinal = dependentTypeMetadata.GetOrdinalforOLayerMemberName(constraint.ToProperties[i].Name);
                    var valueChanging =
                        !ByValueEqualityComparer.Default.Equals(
                            dependentTypeMetadata.Member(dependentOrdinal).GetValue(dependentEntity.Entity), value);
                    if (forceChange || valueChanging)
                    {
                        if (isUnchangedDependent)
                        {
                            ValidateSettingRIConstraints(
                                principalEntity, settingToNull: value == null, changingForeignKeyValue: valueChanging);
                        }
                        if (changedFKs != null)
                        {
                            object previouslySetValue;
                            if (changedFKs.TryGetValue(dependentOrdinal, out previouslySetValue))
                            {
                                if (!ByValueEqualityComparer.Default.Equals(previouslySetValue, value))
                                {
                                    throw new InvalidOperationException(Strings.Update_ReferentialConstraintIntegrityViolation);
                                }
                            }
                            else
                            {
                                changedFKs[dependentOrdinal] = value;
                            }
                        }
                        if (valueChanging)
                        {
                            dependentEntity.SetCurrentValue(
                                dependentEntity.ObjectStateEntry,
                                dependentTypeMetadata.Member(dependentOrdinal),
                                -1,
                                dependentEntity.Entity,
                                value);
                        }
                    }
                    if (numValues > 1)
                    {
                        var 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(
                            value == null ? null : new EntityKey(principalEntitySet, value),
                            dependentEntity.ObjectStateEntry);
                    }
                }
                if (numValues > 1)
                {
                    SetCachedForeignKey(
                        values.Any(v => v == null) ? null : new EntityKey(principalEntitySet, values),
                        dependentEntity.ObjectStateEntry);
                }
                if (WrappedOwner.ObjectStateEntry != null)
                {
                    stateManager.ForgetEntryWithConceptualNull(WrappedOwner.ObjectStateEntry, resetAllKeys: false);
                }
            }
            finally
            {
                stateManager.TransactionManager.EndForeignKeyUpdate();
            }
        }
internal void UpdateForeignKeyValues ( IEntityWrapper dependentEntity , IEntityWrapper principalEntity , Dictionary < int , object > changedFKs , bool forceChange ) { DebugCheck . NotNull ( dependentEntity . Entity ) ; DebugCheck . NotNull ( principalEntity . Entity ) ; Debug . Assert ( IsForeignKey , " " ) ; var constraint = ( ( AssociationType ) RelationMetadata ) . ReferentialConstraints [ 0 ] ; Debug . Assert ( constraint != null , " " ) ; var isUnchangedDependent = ( object ) WrappedOwner . EntityKey != null && ! WrappedOwner . EntityKey . IsTemporary && IsDependentEndOfReferentialConstraint ( checkIdentifying : true ) ; var stateManager = ObjectContext . ObjectStateManager ; stateManager . TransactionManager . BeginForeignKeyUpdate ( this ) ; try { var principalEntitySet = ( ( AssociationSet ) RelationshipSet ) . AssociationSetEnds [ ToEndMember . Name ] . EntitySet ; var principalTypeMetadata = stateManager . GetOrAddStateManagerTypeMetadata ( principalEntity . IdentityType , principalEntitySet ) ; var dependentEntitySet = ( ( AssociationSet ) RelationshipSet ) . AssociationSetEnds [ FromEndMember . Name ] . EntitySet ; var dependentTypeMetadata = stateManager . GetOrAddStateManagerTypeMetadata ( dependentEntity . IdentityType , dependentEntitySet ) ; var principalProps = constraint . FromProperties ; var numValues = principalProps . Count ; string [ ] keyNames = null ; object [ ] values = null ; if ( numValues > 1 ) { keyNames = principalEntitySet . ElementType . KeyMemberNames ; values = new object [ numValues ] ; } for ( var i = 0 ; i < numValues ; i ++ ) { var principalOrdinal = principalTypeMetadata . GetOrdinalforOLayerMemberName ( principalProps [ i ] . Name ) ; var value = principalTypeMetadata . Member ( principalOrdinal ) . GetValue ( principalEntity . Entity ) ; var dependentOrdinal = dependentTypeMetadata . GetOrdinalforOLayerMemberName ( constraint . ToProperties [ i ] . Name ) ; var valueChanging = ! ByValueEqualityComparer . Default . Equals ( dependentTypeMetadata . Member ( dependentOrdinal ) . GetValue ( dependentEntity . Entity ) , value ) ; if ( forceChange || valueChanging ) { if ( isUnchangedDependent ) { ValidateSettingRIConstraints ( principalEntity , settingToNull : value == null , changingForeignKeyValue : valueChanging ) ; } if ( changedFKs != null ) { object previouslySetValue ; if ( changedFKs . TryGetValue ( dependentOrdinal , out previouslySetValue ) ) { if ( ! ByValueEqualityComparer . Default . Equals ( previouslySetValue , value ) ) { throw new InvalidOperationException ( Strings . Update_ReferentialConstraintIntegrityViolation ) ; } } else { changedFKs [ dependentOrdinal ] = value ; } } if ( valueChanging ) { dependentEntity . SetCurrentValue ( dependentEntity . ObjectStateEntry , dependentTypeMetadata . Member ( dependentOrdinal ) , - 1 , dependentEntity . Entity , value ) ; } } if ( numValues > 1 ) { var keyIndex = Array . IndexOf ( keyNames , principalProps [ i ] . Name ) ; Debug . Assert ( keyIndex >= 0 && keyIndex < numValues , " " ) ; values [ keyIndex ] = value ; } else { SetCachedForeignKey ( value == null ? null : new EntityKey ( principalEntitySet , value ) , dependentEntity . ObjectStateEntry ) ; } } if ( numValues > 1 ) { SetCachedForeignKey ( values . Any ( v => v == null ) ? null : new EntityKey ( principalEntitySet , values ) , dependentEntity . ObjectStateEntry ) ; } if ( WrappedOwner . ObjectStateEntry != null ) { stateManager . ForgetEntryWithConceptualNull ( WrappedOwner . ObjectStateEntry , resetAllKeys : false ) ; } } finally { stateManager . TransactionManager . EndForeignKeyUpdate ( ) ; } }
Takes key values from the given principal entity and transfers them to the foreign key properties
of the dependant entry.
Takes key values from the given principal entity and transfers them to the foreign key properties of the dependant entry .
// 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.
dependentEntity
IEntityWrapper
The entity into which foreign key values will be written
The entity into which foreign key values will be written
principalEntity
IEntityWrapper
The entity from which key values will be obtained
The entity from which key values will be obtained
changedFKs
Dictionary<int, object>
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
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
forceChange
bool
If true, then the property setter is called even if FK values already match, which causes the FK properties to be marked as modified.
If true then the property setter is called even if FK values already match which causes the FK properties to be marked as modified .