internal void SetEntityKey(EntityKey value, bool forceFixup) { if (value != null && value == EntityKey && (ReferenceValue.Entity != null || (ReferenceValue.Entity == null && !forceFixup))) { // "no-op" -- this is not really no-op in the attached case, because at a minimum we have to do a key lookup, // worst case we have to review all relationships for the owner entity // However, if we don't do this, we can get into a scenario where we are setting the key to the same thing it's already set to // and this could have side effects, especially with RI constraints and cascade delete. We don't want to delete something // and then add it back, if that deleting could have additional unexpected effects. Don't bother doing this check if value is // null, because EntityKey could be null even if there are Added/Unchanged relationships, if the target entity has a temporary key. // In that case, we still need to delete that existing relationship, so it's not a no-op return; } if (this.ObjectContext != null && !UsingNoTracking) { Debug.Assert(this.WrappedOwner.Entity != null, "Unexpected null Owner on EntityReference attached to a context"); // null is a valid value for the EntityKey, but temporary and special keys are not // devnote: Can't check this on detached references because this property could be set to a temp key during deserialization, // if the key hasn't finished deserializing yet. if (value != null && !IsValidEntityKeyType(value)) { throw EntityUtil.CannotSetSpecialKeys(); } if (value == null) { if (AttemptToNullFKsOnRefOrKeySetToNull()) { DetachedEntityKey = null; } else { ReferenceValue = EntityWrapperFactory.NullWrapper; } } else { // Verify that the key has the right EntitySet for this RelationshipSet EntitySet targetEntitySet = value.GetEntitySet(ObjectContext.MetadataWorkspace); CheckRelationEntitySet(targetEntitySet); value.ValidateEntityKey(ObjectContext.MetadataWorkspace, targetEntitySet, true /*isArgumentException */, "value"); ObjectStateManager manager = this.ObjectContext.ObjectStateManager; // If we already have an entry with this key, we just need to create a relationship with it bool addNewRelationship = false; // If we don't already have any matching entries for this key, we'll have to create a new entry bool addKeyEntry = false; EntityEntry targetEntry = manager.FindEntityEntry(value); if (targetEntry != null) { // If it's not a key entry, just use the entity to set this reference's Value if (!targetEntry.IsKeyEntry) { // Delegate to the Value property to clear any existing relationship // and to add the new one. This will fire the appropriate events and // ensure that the related ends are connected. // It has to be a TEntity since we already verified that the EntitySet is correct above this.ReferenceValue = targetEntry.WrappedEntity; } else { // if the existing entry is a key entry, we just need to // add a new relationship between the source entity and that key addNewRelationship = true; } } else { // no entry exists, so we'll need to add a key along with the relationship addKeyEntry = !IsForeignKey; addNewRelationship = true; } if (addNewRelationship) { EntityKey ownerKey = ValidateOwnerWithRIConstraints(targetEntry == null ? null : targetEntry.WrappedEntity, value, checkBothEnds: true); // Verify that the owner is in a valid state for adding a relationship ValidateStateForAdd(this.WrappedOwner); if (addKeyEntry) { manager.AddKeyEntry(value, targetEntitySet); } // First, clear any existing relationships manager.TransactionManager.EntityBeingReparented = WrappedOwner.Entity; try { ClearCollectionOrRef(null, null, /*doCascadeDelete*/ false); } finally { manager.TransactionManager.EntityBeingReparented = null; } // Then add the new one if (IsForeignKey) { DetachedEntityKey = value; // Update the FK values in this entity if (IsDependentEndOfReferentialConstraint(false)) { UpdateForeignKeyValues(WrappedOwner, value); } } else { RelationshipWrapper wrapper = new RelationshipWrapper((AssociationSet)RelationshipSet, RelationshipNavigation.From, ownerKey, RelationshipNavigation.To, value); // Add the relationship in the unchanged state if EntityState relationshipState = EntityState.Added; // If this is an unchanged/modified dependent end of a relationship and we are allowing the EntityKey to be set // create the relationship in the Unchanged state because the state must "match" the dependent end state if (!ownerKey.IsTemporary && IsDependentEndOfReferentialConstraint(false)) { relationshipState = EntityState.Unchanged; } manager.AddNewRelation(wrapper, relationshipState); } } } } else { // Just set the field for detached object -- during Attach/Add we will make sure this value // is not in conflict if the EntityReference contains a real entity. We cannot always determine the // EntityKey for any real entity in the detached state, so we don't bother to do it here. DetachedEntityKey = value; } }