// <summary> // Call to ensure a target entities key is added into the state manager // properly // </summary> public IEntityWrapper HandleRelationshipSpan( IEntityWrapper wrappedEntity, EntityKey targetKey, AssociationEndMember targetMember) { if (null == wrappedEntity.Entity) { return(wrappedEntity); } DebugCheck.NotNull(targetMember); Debug.Assert( targetMember.RelationshipMultiplicity == RelationshipMultiplicity.One || targetMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne); var sourceKey = wrappedEntity.EntityKey; var sourceMember = MetadataHelper.GetOtherAssociationEnd(targetMember); CheckClearedEntryOnSpan(targetKey, wrappedEntity, sourceKey, targetMember); if (null != (object)targetKey) { EntitySet targetEntitySet; var associationSet = Context.MetadataWorkspace.MetadataOptimization.FindCSpaceAssociationSet( (AssociationType)targetMember.DeclaringType, targetMember.Name, targetKey.EntitySetName, targetKey.EntityContainerName, out targetEntitySet); Debug.Assert(associationSet != null, "associationSet should not be null"); var manager = Context.ObjectStateManager; EntityState newEntryState; // If there is an existing relationship entry, update it based on its current state and the MergeOption, otherwise add a new one if ( !ObjectStateManager.TryUpdateExistingRelationships( Context, MergeOption, associationSet, sourceMember, sourceKey, wrappedEntity, targetMember, targetKey, /*setIsLoaded*/ true, out newEntryState)) { // Try to find a state entry for the target key var targetEntry = manager.GetOrAddKeyEntry(targetKey, targetEntitySet); // For 1-1 relationships we have to take care of the relationships of targetEntity var needNewRelationship = true; switch (sourceMember.RelationshipMultiplicity) { case RelationshipMultiplicity.ZeroOrOne: case RelationshipMultiplicity.One: // devnote: targetEntry can be a key entry (targetEntry.Entity == null), // but it that case this parameter won't be used in TryUpdateExistingRelationships needNewRelationship = !ObjectStateManager.TryUpdateExistingRelationships( Context, MergeOption, associationSet, targetMember, targetKey, targetEntry.WrappedEntity, sourceMember, sourceKey, setIsLoaded: true, newEntryState: out newEntryState); // It is possible that as part of removing existing relationships, the key entry was deleted // If that is the case, recreate the key entry if (targetEntry.State == EntityState.Detached) { targetEntry = manager.AddKeyEntry(targetKey, targetEntitySet); } break; case RelationshipMultiplicity.Many: // we always need a new relationship with Many-To-Many, if there was no exact match between these two entities, so do nothing break; default: Debug.Assert(false, "Unexpected sourceMember.RelationshipMultiplicity"); break; } if (needNewRelationship) { // If the target entry is a key entry, then we need to add a relation // between the source and target entries // If we are in a state where we just need to add a new Deleted relation, we // only need to do that and not touch the related ends // If the target entry is a full entity entry, then we need to add // the target entity to the source collection or reference if (targetEntry.IsKeyEntry || newEntryState == EntityState.Deleted) { // Add a relationship between the source entity and the target key entry var wrapper = new RelationshipWrapper( associationSet, sourceMember.Name, sourceKey, targetMember.Name, targetKey); manager.AddNewRelation(wrapper, newEntryState); } else { Debug.Assert(!targetEntry.IsRelationship, "how IsRelationship?"); if (targetEntry.State != EntityState.Deleted) { // The entry contains an entity, do collection or reference fixup // This will also try to create a new relationship entry or will revert the delete on an existing deleted relationship ObjectStateManager.AddEntityToCollectionOrReference( MergeOption, wrappedEntity, sourceMember, targetEntry.WrappedEntity, targetMember, setIsLoaded: true, relationshipAlreadyExists: false, inKeyEntryPromotion: false); } else { // if the target entry is deleted, then the materializer needs to create a deleted relationship // between the entity and the target entry so that if the entity is deleted, the update // pipeline can find the relationship (even though it is deleted) var wrapper = new RelationshipWrapper( associationSet, sourceMember.Name, sourceKey, targetMember.Name, targetKey); manager.AddNewRelation(wrapper, EntityState.Deleted); } } } } } else { RelatedEnd relatedEnd; if (TryGetRelatedEnd( wrappedEntity, (AssociationType)targetMember.DeclaringType, sourceMember.Name, targetMember.Name, out relatedEnd)) { SetIsLoadedForSpan(relatedEnd, false); } } // else there is nothing else for us to do, the relationship has been handled already return(wrappedEntity); }
public IEntityWrapper HandleRelationshipSpan( IEntityWrapper wrappedEntity, EntityKey targetKey, AssociationEndMember targetMember) { if (wrappedEntity.Entity == null) { return(wrappedEntity); } EntityKey entityKey = wrappedEntity.EntityKey; AssociationEndMember otherAssociationEnd = MetadataHelper.GetOtherAssociationEnd(targetMember); this.CheckClearedEntryOnSpan((object)targetKey, wrappedEntity, entityKey, targetMember); if ((object)targetKey != null) { EntitySet endEntitySet; AssociationSet cspaceAssociationSet = this.Context.MetadataWorkspace.MetadataOptimization.FindCSpaceAssociationSet((AssociationType)targetMember.DeclaringType, targetMember.Name, targetKey.EntitySetName, targetKey.EntityContainerName, out endEntitySet); ObjectStateManager objectStateManager = this.Context.ObjectStateManager; EntityState newEntryState; if (!ObjectStateManager.TryUpdateExistingRelationships(this.Context, this.MergeOption, cspaceAssociationSet, otherAssociationEnd, entityKey, wrappedEntity, targetMember, targetKey, true, out newEntryState)) { EntityEntry entityEntry = objectStateManager.GetOrAddKeyEntry(targetKey, endEntitySet); bool flag = true; switch (otherAssociationEnd.RelationshipMultiplicity) { case RelationshipMultiplicity.ZeroOrOne: case RelationshipMultiplicity.One: flag = !ObjectStateManager.TryUpdateExistingRelationships(this.Context, this.MergeOption, cspaceAssociationSet, targetMember, targetKey, entityEntry.WrappedEntity, otherAssociationEnd, entityKey, true, out newEntryState); if (entityEntry.State == EntityState.Detached) { entityEntry = objectStateManager.AddKeyEntry(targetKey, endEntitySet); break; } break; } if (flag) { if (entityEntry.IsKeyEntry || newEntryState == EntityState.Deleted) { RelationshipWrapper wrapper = new RelationshipWrapper(cspaceAssociationSet, otherAssociationEnd.Name, entityKey, targetMember.Name, targetKey); objectStateManager.AddNewRelation(wrapper, newEntryState); } else if (entityEntry.State != EntityState.Deleted) { ObjectStateManager.AddEntityToCollectionOrReference(this.MergeOption, wrappedEntity, otherAssociationEnd, entityEntry.WrappedEntity, targetMember, true, false, false); } else { RelationshipWrapper wrapper = new RelationshipWrapper(cspaceAssociationSet, otherAssociationEnd.Name, entityKey, targetMember.Name, targetKey); objectStateManager.AddNewRelation(wrapper, EntityState.Deleted); } } } } else { RelatedEnd relatedEnd; if (this.TryGetRelatedEnd(wrappedEntity, (AssociationType)targetMember.DeclaringType, otherAssociationEnd.Name, targetMember.Name, out relatedEnd)) { this.SetIsLoadedForSpan(relatedEnd, false); } } return(wrappedEntity); }