src/Shared/EntityFramework/Core/Objects/DataClasses/EntityReference.cs
// <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>
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.
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 .
internal void NullAllForeignKeys()
        {
            Debug.Assert(ObjectContext != null, "Nulling FKs only works when attached.");
            Debug.Assert(IsForeignKey, "Cannot null FKs for independent associations.");
            var stateManager = ObjectContext.ObjectStateManager;
            var entry = WrappedOwner.ObjectStateEntry;
            var transManager = stateManager.TransactionManager;
            if (!transManager.IsGraphUpdate
                && !transManager.IsAttachTracking
                && !transManager.IsRelatedEndAdd)
            {
                var constraint = ((AssociationType)RelationMetadata).ReferentialConstraints.Single();
                if (TargetRoleName == constraint.FromRole.Name) 
                {
                    if (transManager.IsDetaching)
                    {
                        Debug.Assert(entry != null, "State entry must exist while detaching.");
                        var foreignKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                        if (foreignKey != null)
                        {
                            stateManager.AddEntryContainingForeignKeyToIndex(this, foreignKey, entry);
                        }
                    }
                    else if (!ReferenceEquals(stateManager.EntityInvokingFKSetter, WrappedOwner.Entity)
                             && !transManager.IsForeignKeyUpdate)
                    {
                        transManager.BeginForeignKeyUpdate(this);
                        try
                        {
                            var unableToNull = true;
                            var canSetModifiedProps = entry != null
                                                      && (entry.State == EntityState.Modified || entry.State == EntityState.Unchanged);
                            var dependentEntitySet = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndMember.Name].EntitySet;
                            var dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(
                                WrappedOwner.IdentityType, dependentEntitySet);
                            for (var i = 0; i < constraint.FromProperties.Count; i++)
                            {
                                var propertyName = constraint.ToProperties[i].Name;
                                var dependentOrdinal = dependentTypeMetadata.GetOrdinalforOLayerMemberName(propertyName);
                                var member = dependentTypeMetadata.Member(dependentOrdinal);
                                if (member.ClrMetadata.Nullable)
                                {
                                    if (member.GetValue(WrappedOwner.Entity) != null)
                                    {
                                        WrappedOwner.SetCurrentValue(
                                            WrappedOwner.ObjectStateEntry,
                                            dependentTypeMetadata.Member(dependentOrdinal),
                                            -1,
                                            WrappedOwner.Entity,
                                            null);
                                    }
                                    else
                                    {
                                        if (canSetModifiedProps
                                            && WrappedOwner.ObjectStateEntry.OriginalValues.GetValue(dependentOrdinal) != null)
                                        {
                                            entry.SetModifiedProperty(propertyName);
                                        }
                                    }
                                    unableToNull = false;
                                }
                                else if (canSetModifiedProps)
                                {
                                    entry.SetModifiedProperty(propertyName);
                                }
                            }
                            if (unableToNull)
                            {
                                if (entry != null)
                                {
                                    var realKey = CachedForeignKey;
                                    if (realKey == null)
                                    {
                                        realKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                                    }
                                    if (realKey != null)
                                    {
                                        SetCachedForeignKey(ForeignKeyFactory.CreateConceptualNullKey(realKey), entry);
                                        stateManager.RememberEntryWithConceptualNull(entry);
                                    }
                                }
                            }
                            else
                            {
                                SetCachedForeignKey(null, entry);
                            }
                        }
                        finally
                        {
                            transManager.EndForeignKeyUpdate();
                        }
                    }
                }
            }
        }
internal void NullAllForeignKeys ( ) { Debug . Assert ( ObjectContext != null , " " ) ; Debug . Assert ( IsForeignKey , " " ) ; var stateManager = ObjectContext . ObjectStateManager ; var entry = WrappedOwner . ObjectStateEntry ; var transManager = stateManager . TransactionManager ; if ( ! transManager . IsGraphUpdate && ! transManager . IsAttachTracking && ! transManager . IsRelatedEndAdd ) { var constraint = ( ( AssociationType ) RelationMetadata ) . ReferentialConstraints . Single ( ) ; if ( TargetRoleName == constraint . FromRole . Name ) { if ( transManager . IsDetaching ) { Debug . Assert ( entry != null , " " ) ; var foreignKey = ForeignKeyFactory . CreateKeyFromForeignKeyValues ( entry , this ) ; if ( foreignKey != null ) { stateManager . AddEntryContainingForeignKeyToIndex ( this , foreignKey , entry ) ; } } else if ( ! ReferenceEquals ( stateManager . EntityInvokingFKSetter , WrappedOwner . Entity ) && ! transManager . IsForeignKeyUpdate ) { transManager . BeginForeignKeyUpdate ( this ) ; try { var unableToNull = true ; var canSetModifiedProps = entry != null && ( entry . State == EntityState . Modified || entry . State == EntityState . Unchanged ) ; var dependentEntitySet = ( ( AssociationSet ) RelationshipSet ) . AssociationSetEnds [ FromEndMember . Name ] . EntitySet ; var dependentTypeMetadata = stateManager . GetOrAddStateManagerTypeMetadata ( WrappedOwner . IdentityType , dependentEntitySet ) ; for ( var i = 0 ; i < constraint . FromProperties . Count ; i ++ ) { var propertyName = constraint . ToProperties [ i ] . Name ; var dependentOrdinal = dependentTypeMetadata . GetOrdinalforOLayerMemberName ( propertyName ) ; var member = dependentTypeMetadata . Member ( dependentOrdinal ) ; if ( member . ClrMetadata . Nullable ) { if ( member . GetValue ( WrappedOwner . Entity ) != null ) { WrappedOwner . SetCurrentValue ( WrappedOwner . ObjectStateEntry , dependentTypeMetadata . Member ( dependentOrdinal ) , - 1 , WrappedOwner . Entity , null ) ; } else { if ( canSetModifiedProps && WrappedOwner . ObjectStateEntry . OriginalValues . GetValue ( dependentOrdinal ) != null ) { entry . SetModifiedProperty ( propertyName ) ; } } unableToNull = false ; } else if ( canSetModifiedProps ) { entry . SetModifiedProperty ( propertyName ) ; } } if ( unableToNull ) { if ( entry != null ) { var realKey = CachedForeignKey ; if ( realKey == null ) { realKey = ForeignKeyFactory . CreateKeyFromForeignKeyValues ( entry , this ) ; } if ( realKey != null ) { SetCachedForeignKey ( ForeignKeyFactory . CreateConceptualNullKey ( realKey ) , entry ) ; stateManager . RememberEntryWithConceptualNull ( entry ) ; } } } else { SetCachedForeignKey ( null , entry ) ; } } finally { transManager . EndForeignKeyUpdate ( ) ; } } } } }
Attempts to null all FKs associated with the dependent end of this relationship on this entity.
Attempts to null all FKs associated with the dependent end of this relationship on this entity .
// Only do this on the dependent end // 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. // 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. // Only set the value to null if it is not already null. // 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. // 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 //The CachedForeignKey may be null if we are putting //back a Conceptual Null as part of roll back // 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.