예제 #1
0
        /// <summary>
        /// Gets the NavigationProperty that allows you to navigate from entity represented
        /// by the localEnd to the entity represented by the foreignEnd.
        /// </summary>
        private NavigationProperty getProperty(ObjectStateEntry entry,
                                               AssociationEndMember localEnd, AssociationEndMember foreignEnd,
                                               EntityKey key)
        {
            var relationshipType = entry.EntitySet.ElementType;
            var entitySet        = key.GetEntitySet(entry.ObjectStateManager.MetadataWorkspace);

            return(entitySet.ElementType.NavigationProperties
                   .Where(p => p.RelationshipType == relationshipType &&
                          p.FromEndMember == localEnd &&
                          p.ToEndMember == foreignEnd)
                   .SingleOrDefault());
        }
예제 #2
0
        // Note that this is called only for association ends. Entities have key values inline.
        private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey)
        {
            // get metadata for key
            var entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType;
            var keyRowType = entityType.GetKeyRowType();

            var keyMetadata    = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType);
            var keyMemberCount = keyRowType.Properties.Count;
            var keyValues      = new PropagatorResult[keyMemberCount];

            for (var ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++)
            {
                EdmMember keyMember = keyRowType.Properties[ordinal];
                // retrieve information about this key value
                var keyMemberInformation = keyMetadata.m_memberMap[ordinal];

                var keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count);

                object keyValue = null;
                if (entityKey.IsTemporary)
                {
                    // If the EntityKey is temporary, we need to retrieve the appropriate
                    // key value from the entity itself (or in this case, the IEntityStateEntry).
                    var entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey);
                    Debug.Assert(
                        entityEntry.State == EntityState.Added,
                        "The corresponding entry for a temp EntityKey should be in the Added State.");
                    keyValue = entityEntry.CurrentValues[keyMember.Name];
                }
                else
                {
                    // Otherwise, we extract the value from within the EntityKey.
                    keyValue = entityKey.FindValueByName(keyMember.Name);
                }
                Debug.Assert(keyValue != null, "keyValue should've been retrieved.");

                // construct propagator result
                keyValues[ordinal] = PropagatorResult.CreateKeyValue(
                    keyMemberInformation.Flags,
                    keyValue,
                    stateEntry,
                    keyIdentifier);

                // see UpdateTranslator.Identifiers for information on key identifiers and ordinals
            }

            return(PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false));
        }
예제 #3
0
        internal override void ValidateDetachedEntityKey()
        {
            if (!this.IsEmpty() || !(this.DetachedEntityKey != (EntityKey)null))
            {
                return;
            }
            EntityKey detachedEntityKey = this.DetachedEntityKey;

            if (!RelatedEnd.IsValidEntityKeyType(detachedEntityKey))
            {
                throw Error.EntityReference_CannotSetSpecialKeys();
            }
            EntitySet entitySet = detachedEntityKey.GetEntitySet(this.ObjectContext.MetadataWorkspace);

            this.CheckRelationEntitySet(entitySet);
            detachedEntityKey.ValidateEntityKey(this.ObjectContext.MetadataWorkspace, entitySet);
        }
        private PropagatorResult CreateEntityKeyResult(
            IEntityStateEntry stateEntry,
            EntityKey entityKey)
        {
            RowType           keyRowType        = entityKey.GetEntitySet(this.m_translator.MetadataWorkspace).ElementType.GetKeyRowType();
            ExtractorMetadata extractorMetadata = this.m_translator.GetExtractorMetadata(stateEntry.EntitySet, (StructuralType)keyRowType);

            PropagatorResult[] values = new PropagatorResult[keyRowType.Properties.Count];
            for (int memberOffset = 0; memberOffset < keyRowType.Properties.Count; ++memberOffset)
            {
                EdmMember property = (EdmMember)keyRowType.Properties[memberOffset];
                ExtractorMetadata.MemberInformation member = extractorMetadata.m_memberMap[memberOffset];
                int    identifierForMemberOffset           = this.m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, memberOffset, keyRowType.Properties.Count);
                object obj = !entityKey.IsTemporary ? entityKey.FindValueByName(property.Name) : stateEntry.StateManager.GetEntityStateEntry(entityKey).CurrentValues[property.Name];
                values[memberOffset] = PropagatorResult.CreateKeyValue(member.Flags, obj, stateEntry, identifierForMemberOffset);
            }
            return(PropagatorResult.CreateStructuralValue(values, extractorMetadata.m_type, false));
        }
예제 #5
0
        public IEnumerable <T2> GetAssociationChanges <T1, T2>(T1 parent, string propertyName, EntityState findState)
        {
            ObjectContext     ocontext          = ((IObjectContextAdapter)this.context).ObjectContext;
            MetadataWorkspace metadataWorkspace = ocontext.MetadataWorkspace;

            // Find the AssociationType that matches the property traits given as input
            AssociationType atype =
                metadataWorkspace.GetItems <AssociationType>(DataSpace.CSpace)
                .Where(a => a.AssociationEndMembers.Any(
                           ae => ae.MetadataProperties.Any(mp => mp.Name == "ClrPropertyInfo" && // Magic string!!!
                                                           ((PropertyInfo)mp.Value).Name == propertyName &&
                                                           typeof(T1).IsAssignableFrom(((PropertyInfo)mp.Value).DeclaringType)
                                                           )
                           )
                       ).First();

            // Find added or deleted DbDataRecords from the above discovered type
            ocontext.DetectChanges();
            IEnumerable <DbDataRecord> dbDataRecords = ocontext.ObjectStateManager
                                                       .GetObjectStateEntries(findState)
                                                       .Where(e => e.IsRelationship)
                                                       // Oddly, this works, while doing the same thing below requires comparing .Name...?
                                                       .Where(e => e.EntitySet.ElementType == atype)
                                                       .Select(e => findState == EntityState.Deleted ? e.OriginalValues : e.CurrentValues);

            // Get the actual entities using the EntityKeys in the DbDataRecord
            IList <T2> relationChanges = new List <T2>();

            foreach (System.Data.Common.DbDataRecord ddr in dbDataRecords)
            {
                EntityKey ek = (EntityKey)ddr[0];
                // Comparing .ElementType to atype doesn't work, see above...?
                if (!(ek.GetEntitySet(metadataWorkspace).ElementType.Name == atype.Name))
                {
                    ek = (EntityKey)ddr[1];
                }
                relationChanges.Add((T2)ocontext.GetObjectByKey(ek));
            }
            return(relationChanges);
        }
예제 #6
0
        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 (ObjectContext != null
                && !UsingNoTracking)
            {
                Debug.Assert(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 new ArgumentException(Strings.EntityReference_CannotSetSpecialKeys, "value");
                }

                if (value == null)
                {
                    if (AttemptToNullFKsOnRefOrKeySetToNull())
                    {
                        DetachedEntityKey = null;
                    }
                    else
                    {
                        ReferenceValue = NullEntityWrapper.NullWrapper;
                    }
                }
                else
                {
                    // Verify that the key has the right EntitySet for this RelationshipSet
                    var targetEntitySet = value.GetEntitySet(ObjectContext.MetadataWorkspace);
                    CheckRelationEntitySet(targetEntitySet);
                    value.ValidateEntityKey(ObjectContext.MetadataWorkspace, targetEntitySet, true /*isArgumentException */, "value");

                    var manager = ObjectContext.ObjectStateManager;

                    // If we already have an entry with this key, we just need to create a relationship with it
                    var addNewRelationship = false;
                    // If we don't already have any matching entries for this key, we'll have to create a new entry
                    var addKeyEntry = false;
                    var 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
                            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)
                    {
                        var ownerKey = ValidateOwnerWithRIConstraints(
                            targetEntry == null ? null : targetEntry.WrappedEntity, value, checkBothEnds: true);

                        // Verify that the owner is in a valid state for adding a relationship
                        ValidateStateForAdd(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
                        {
                            var wrapper = new RelationshipWrapper(
                                (AssociationSet)RelationshipSet, RelationshipNavigation.From, ownerKey, RelationshipNavigation.To, value);
                            // Add the relationship in the unchanged state if
                            var 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;
            }
        }
예제 #7
0
        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;
            }
        }
예제 #8
0
 internal void SetEntityKey(EntityKey value, bool forceFixup)
 {
     if (value != (EntityKey)null && value == this.EntityKey && (this.ReferenceValue.Entity != null || this.ReferenceValue.Entity == null && !forceFixup))
     {
         return;
     }
     if (this.ObjectContext != null && !this.UsingNoTracking)
     {
         if (value != (EntityKey)null && !RelatedEnd.IsValidEntityKeyType(value))
         {
             throw new ArgumentException(Strings.EntityReference_CannotSetSpecialKeys, nameof(value));
         }
         if (value == (EntityKey)null)
         {
             if (this.AttemptToNullFKsOnRefOrKeySetToNull())
             {
                 this.DetachedEntityKey = (EntityKey)null;
             }
             else
             {
                 this.ReferenceValue = NullEntityWrapper.NullWrapper;
             }
         }
         else
         {
             EntitySet entitySet = value.GetEntitySet(this.ObjectContext.MetadataWorkspace);
             this.CheckRelationEntitySet(entitySet);
             value.ValidateEntityKey(this.ObjectContext.MetadataWorkspace, entitySet, true, nameof(value));
             ObjectStateManager objectStateManager = this.ObjectContext.ObjectStateManager;
             bool        flag1       = false;
             bool        flag2       = false;
             EntityEntry entityEntry = objectStateManager.FindEntityEntry(value);
             if (entityEntry != null)
             {
                 if (!entityEntry.IsKeyEntry)
                 {
                     this.ReferenceValue = entityEntry.WrappedEntity;
                 }
                 else
                 {
                     flag1 = true;
                 }
             }
             else
             {
                 flag2 = !this.IsForeignKey;
                 flag1 = true;
             }
             if (!flag1)
             {
                 return;
             }
             EntityKey key0 = this.ValidateOwnerWithRIConstraints(entityEntry == null ? (IEntityWrapper)null : entityEntry.WrappedEntity, value, true);
             this.ValidateStateForAdd(this.WrappedOwner);
             if (flag2)
             {
                 objectStateManager.AddKeyEntry(value, entitySet);
             }
             objectStateManager.TransactionManager.EntityBeingReparented = this.WrappedOwner.Entity;
             try
             {
                 this.ClearCollectionOrRef((IEntityWrapper)null, (RelationshipNavigation)null, false);
             }
             finally
             {
                 objectStateManager.TransactionManager.EntityBeingReparented = (object)null;
             }
             if (this.IsForeignKey)
             {
                 this.DetachedEntityKey = value;
                 if (!this.IsDependentEndOfReferentialConstraint(false))
                 {
                     return;
                 }
                 this.UpdateForeignKeyValues(this.WrappedOwner, value);
             }
             else
             {
                 RelationshipWrapper wrapper      = new RelationshipWrapper((AssociationSet)this.RelationshipSet, this.RelationshipNavigation.From, key0, this.RelationshipNavigation.To, value);
                 EntityState         desiredState = EntityState.Added;
                 if (!key0.IsTemporary && this.IsDependentEndOfReferentialConstraint(false))
                 {
                     desiredState = EntityState.Unchanged;
                 }
                 objectStateManager.AddNewRelation(wrapper, desiredState);
             }
         }
     }
     else
     {
         this.DetachedEntityKey = value;
     }
 }
        // Note that this is called only for association ends. Entities have key values inline.
        private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey)
        {
            // get metadata for key
            var entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType;
            var keyRowType = entityType.GetKeyRowType();

            var keyMetadata = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType);
            var keyMemberCount = keyRowType.Properties.Count;
            var keyValues = new PropagatorResult[keyMemberCount];

            for (var ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++)
            {
                EdmMember keyMember = keyRowType.Properties[ordinal];
                // retrieve information about this key value
                var keyMemberInformation = keyMetadata.m_memberMap[ordinal];

                var keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count);

                object keyValue = null;
                if (entityKey.IsTemporary)
                {
                    // If the EntityKey is temporary, we need to retrieve the appropriate
                    // key value from the entity itself (or in this case, the IEntityStateEntry).
                    var entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey);
                    Debug.Assert(
                        entityEntry.State == EntityState.Added,
                        "The corresponding entry for a temp EntityKey should be in the Added State.");
                    keyValue = entityEntry.CurrentValues[keyMember.Name];
                }
                else
                {
                    // Otherwise, we extract the value from within the EntityKey.
                    keyValue = entityKey.FindValueByName(keyMember.Name);
                }
                Debug.Assert(keyValue != null, "keyValue should've been retrieved.");

                // construct propagator result
                keyValues[ordinal] = PropagatorResult.CreateKeyValue(
                    keyMemberInformation.Flags,
                    keyValue,
                    stateEntry,
                    keyIdentifier);

                // see UpdateTranslator.Identifiers for information on key identifiers and ordinals
            }

            return PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false);
        }