/// <summary> /// Method called by proxy interceptor delegate to provide lazy loading behavior for navigation properties. /// </summary> /// <typeparam name="TItem">property type</typeparam> /// <param name="propertyValue">The property value whose associated relationship is to be loaded.</param> /// <param name="relationshipName">String name of the relationship.</param> /// <param name="targetRoleName">String name of the related end to be loaded for the relationship specified by <paramref name="relationshipName"/>.</param> /// <param name="wrapperObject">Entity wrapper object used to retrieve RelationshipManager for the proxied entity.</param> /// <returns> /// True if the value instance was mutated and can be returned /// False if the class should refetch the value because the instance has changed /// </returns> private static bool LoadProperty <TItem>(TItem propertyValue, string relationshipName, string targetRoleName, bool mustBeNull, object wrapperObject) where TItem : class { // Only attempt to load collection if: // // 1. Collection is non-null. // 2. ObjectContext.ContextOptions.LazyLoadingEnabled is true // 3. A non-null RelationshipManager can be retrieved (this is asserted). // 4. The EntityCollection is not already loaded. Debug.Assert(wrapperObject == null || wrapperObject is IEntityWrapper, "wrapperObject must be an IEntityWrapper"); IEntityWrapper wrapper = (IEntityWrapper)wrapperObject; // We want an exception if the cast fails. if (wrapper != null && wrapper.Context != null) { RelationshipManager relationshipManager = wrapper.RelationshipManager; Debug.Assert(relationshipManager != null, "relationshipManager should be non-null"); if (relationshipManager != null && (!mustBeNull || propertyValue == null)) { RelatedEnd relatedEnd = relationshipManager.GetRelatedEndInternal(relationshipName, targetRoleName); relatedEnd.DeferredLoad(); } } return(propertyValue != null); }
private static bool LoadProperty <TItem>( TItem propertyValue, string relationshipName, string targetRoleName, bool mustBeNull, object wrapperObject) where TItem : class { IEntityWrapper entityWrapper = (IEntityWrapper)wrapperObject; if (entityWrapper != null && entityWrapper.Context != null) { RelationshipManager relationshipManager = entityWrapper.RelationshipManager; if (relationshipManager != null && (!mustBeNull || (object)propertyValue == null)) { relationshipManager.GetRelatedEndInternal(relationshipName, targetRoleName).DeferredLoad(); } } return((object)propertyValue != null); }
//"doFixup" equals to False is called from EntityCollection & Ref code only internal void Delete(bool doFixup) { ValidateState(); if (doFixup) { if (State != EntityState.Deleted) //for deleted ObjectStateEntry its a no-op { //Find two ends of the relationship var entry1 = _cache.GetEntityEntry((EntityKey)GetCurrentRelationValue(0)); var wrappedEntity1 = entry1.WrappedEntity; var entry2 = _cache.GetEntityEntry((EntityKey)GetCurrentRelationValue(1)); var wrappedEntity2 = entry2.WrappedEntity; // If one end of the relationship is a KeyEntry, entity1 or entity2 is null. // It is not possible that both ends of relationship are KeyEntries. if (wrappedEntity1.Entity != null && wrappedEntity2.Entity != null) { // Obtain the ro role name and relationship name // We don't create a full NavigationRelationship here because that would require looking up // additional information like property names that we don't need. var endMembers = _relationshipWrapper.AssociationEndMembers; var toRole = endMembers[1].Name; var relationshipName = ((AssociationSet)_entitySet).ElementType.FullName; wrappedEntity1.RelationshipManager.RemoveEntity(toRole, relationshipName, wrappedEntity2); } else { // One end of relationship is a KeyEntry, figure out which one is the real entity and get its RelationshipManager // so we can update the DetachedEntityKey on the EntityReference associated with this relationship EntityKey targetKey = null; RelationshipManager relationshipManager = null; if (wrappedEntity1.Entity == null) { targetKey = entry1.EntityKey; relationshipManager = wrappedEntity2.RelationshipManager; } else { targetKey = entry2.EntityKey; relationshipManager = wrappedEntity1.RelationshipManager; } Debug.Assert(relationshipManager != null, "Entity wrapper returned a null RelationshipManager"); // Clear the detachedEntityKey as well. In cases where we have to fix up the detachedEntityKey, we will not always be able to detect // if we have *only* a Deleted relationship for a given entity/relationship/role, so clearing this here will ensure that // even if no other relationships are added, the key value will still be correct and we won't accidentally pick up an old value. // devnote: Since we know the target end of this relationship is a key entry, it has to be a reference, so just cast var targetMember = RelationshipWrapper.GetAssociationEndMember(targetKey); var entityReference = (EntityReference) relationshipManager.GetRelatedEndInternal(targetMember.DeclaringType.FullName, targetMember.Name); entityReference.DetachedEntityKey = null; // Now update the state if (State == EntityState.Added) { // Remove key entry if necessary DeleteUnnecessaryKeyEntries(); // Remove relationship entry // devnote: Using this method instead of just changing the state because the entry // may have already been detached along with the key entry above. However, // if there were other relationships using the key, it would not have been deleted. DetachRelationshipEntry(); } else { // Non-added entries should be deleted _cache.ChangeState(this, State, EntityState.Deleted); State = EntityState.Deleted; } } } } else { switch (State) { case EntityState.Added: // Remove key entry if necessary DeleteUnnecessaryKeyEntries(); // Remove relationship entry // devnote: Using this method instead of just changing the state because the entry // may have already been detached along with the key entry above. However, // if there were other relationships using the key, it would not have been deleted. DetachRelationshipEntry(); break; case EntityState.Modified: Debug.Assert(false, "RelationshipEntry cannot be in Modified state"); break; case EntityState.Unchanged: _cache.ChangeState(this, EntityState.Unchanged, EntityState.Deleted); State = EntityState.Deleted; break; //case DataRowState.Deleted: no-op } } }