Beispiel #1
0
        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
        {
            Debug.Assert(RelationshipNavigation != null, "null RelationshipNavigation");

            // If the navigation property doesn't exist (e.g. unidirectional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty)
            {
                return(false);
            }

            var value = WrappedOwner.GetNavigationPropertyValue(this);

            if (value != null)
            {
                var enumerable = value as IEnumerable;
                if (enumerable == null)
                {
                    throw new EntityException(
                              Strings.ObjectStateEntry_UnableToEnumerateCollection(
                                  TargetAccessor.PropertyName, WrappedOwner.Entity.GetType().FullName));
                }

                foreach (var o in enumerable)
                {
                    if (Equals(o, wrapper.Entity))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Beispiel #2
0
        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
        {
            Debug.Assert(RelationshipNavigation != null, "null RelationshipNavigation");

            // If the navigation property doesn't exist (e.g. unidirectional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty)
            {
                return(false);
            }

            var loadingState = DisableLazyLoading();

            try
            {
                var value = WrappedOwner.GetNavigationPropertyValue(this);

                if (value != null)
                {
                    // It would be good to be able to always use ICollection<T>.Contains here. The problem
                    // is if the entity has overridden Equals/GetHashcode such that it makes use of the
                    // primary key value then this will break when an Added object with an Identity key that
                    // is contained in a navigation collection has its primary key set after it is saved.
                    // Therefore, we only use this optimization if we know for sure that the nav prop is
                    // using reference equality or if neither Equals or GetHashCode are overridden.
                    //
                    // Also, note that for most EF code to work the navigation property must be an ICollection.
                    // However, some limited code paths work with IEnumerable, so we check for IEnumerable here
                    // instead of ICollection to avoid breaking those code paths. If it's not IEnumerable, then
                    // the message still tells people to use ICollection since pointing them to use IEnumerable
                    // will likely cause more confusion and other errors as they continue development.
                    var enumerable = value as IEnumerable <TEntity>;
                    if (enumerable == null)
                    {
                        throw new EntityException(
                                  Strings.ObjectStateEntry_UnableToEnumerateCollection(
                                      TargetAccessor.PropertyName, WrappedOwner.Entity.GetType().FullName));
                    }

                    var hashSet = value as HashSet <TEntity>;
                    if (!wrapper.OverridesEqualsOrGetHashCode ||
                        (hashSet != null &&
                         hashSet.Comparer is ObjectReferenceEqualityComparer))
                    {
                        // Contains extension method will short-circuit to ICollection.Contains if possible
                        return(enumerable.Contains((TEntity)wrapper.Entity));
                    }

                    return(enumerable.Any(o => ReferenceEquals(o, wrapper.Entity)));
                }
            }
            finally
            {
                ResetLazyLoading(loadingState);
            }

            return(false);
        }
Beispiel #3
0
        internal override void AddToObjectCache(IEntityWrapper wrappedEntity)
        {
            DebugCheck.NotNull(wrappedEntity);

            // For POCO entities - add the object to the CLR collection
            if (TargetAccessor.HasProperty) // Null if the navigation does not exist in this direction
            {
                WrappedOwner.CollectionAdd(this, wrappedEntity.Entity);
            }
        }
Beispiel #4
0
        internal override void AddToObjectCache(IEntityWrapper wrappedEntity)
        {
            DebugCheck.NotNull(wrappedEntity);

            // For POCO entities - set the CLR reference
            if (TargetAccessor.HasProperty)
            {
                WrappedOwner.SetNavigationPropertyValue(this, wrappedEntity.Entity);
            }
        }
 internal override void VerifyNavigationPropertyForAdd(IEntityWrapper wrapper)
 {
     if (this.TargetAccessor.HasProperty)
     {
         object value = WrappedOwner.GetNavigationPropertyValue(this);
         if (!Object.ReferenceEquals(null, value) && !Object.Equals(value, wrapper.Entity))
         {
             throw EntityUtil.CannotAddMoreThanOneEntityToEntityReference(
                       this.RelationshipNavigation.To, this.RelationshipNavigation.RelationshipName);
         }
     }
 }
Beispiel #6
0
        // <summary>
        // Remove from the POCO collection
        // </summary>
        internal override bool RemoveFromObjectCache(IEntityWrapper wrappedEntity)
        {
            DebugCheck.NotNull(wrappedEntity);

            // For POCO entities - remove the object from the CLR collection
            if (TargetAccessor.HasProperty) // Null if the navigation does not exist in this direction
            {
                return(WrappedOwner.CollectionRemove(this, wrappedEntity.Entity));
            }

            return(false);
        }
Beispiel #7
0
        // <summary>
        // Remove from the POCO collection
        // </summary>
        internal override bool RemoveFromObjectCache(IEntityWrapper wrappedEntity)
        {
            DebugCheck.NotNull(wrappedEntity);

            // For POCO entities - clear the CLR reference
            if (TargetAccessor.HasProperty)
            {
                WrappedOwner.RemoveNavigationPropertyValue(this, wrappedEntity.Entity);
            }

            return(true);
        }
Beispiel #8
0
 internal override void VerifyNavigationPropertyForAdd(IEntityWrapper wrapper)
 {
     if (TargetAccessor.HasProperty)
     {
         var value = WrappedOwner.GetNavigationPropertyValue(this);
         if (!ReferenceEquals(null, value) &&
             !ReferenceEquals(value, wrapper.Entity))
         {
             throw new InvalidOperationException(
                       Strings.EntityReference_CannotAddMoreThanOneEntityToEntityReference(
                           RelationshipNavigation.To, RelationshipNavigation.RelationshipName));
         }
     }
 }
Beispiel #9
0
        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
        {
            Debug.Assert(RelationshipNavigation != null, "null RelationshipNavigation");

            // If the navigation property doesn't exist (e.g. unidirectional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty)
            {
                return(false);
            }

            var value = WrappedOwner.GetNavigationPropertyValue(this);

            return(ReferenceEquals(value, wrapper.Entity));
        }
        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
        {
            Debug.Assert(RelationshipNavigation != null, "null RelationshipNavigation");

            // If the navigation property doesn't exist (e.g. unidirectional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty)
            {
                return(false);
            }

            var value = WrappedOwner.GetNavigationPropertyValue(this);

            if (value != null)
            {
                // It would be good to be able to always use ICollection<T>.Contains here. The problem
                // is if the entity has overridden Equals/GetHashcode such that it makes use of the
                // primary key value then this will break when an Added object with an Identity key that
                // is contained in a navigation collection has its primary key set after it is saved.
                // Therefore, we only use this optimization if we know for sure that the nav prop is
                // using reference equality or if neither Equals or GetHashCode are overridden.

                var collection = value as ICollection <TEntity>;
                if (collection == null)
                {
                    throw new EntityException(
                              Strings.ObjectStateEntry_UnableToEnumerateCollection(
                                  TargetAccessor.PropertyName, WrappedOwner.Entity.GetType().FullName));
                }

                var hashSet = value as HashSet <TEntity>;
                if (!wrapper.OverridesEqualsOrGetHashCode ||
                    (hashSet != null &&
                     hashSet.Comparer is ObjectReferenceEqualityComparer))
                {
                    return(collection.Contains((TEntity)wrapper.Entity));
                }

                return(collection.Any(o => ReferenceEquals(o, wrapper.Entity)));
            }
            return(false);
        }
Beispiel #11
0
        /// <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>
        internal void NullAllForeignKeys()
        {
            Debug.Assert(ObjectContext != null, "Nulling FKs only works when attached.");
            Debug.Assert(IsForeignKey, "Cannot null FKs for independent associations.");

            ObjectStateManager stateManager = ObjectContext.ObjectStateManager;
            EntityEntry        entry        = WrappedOwner.ObjectStateEntry;
            TransactionManager transManager = stateManager.TransactionManager;

            if (!transManager.IsGraphUpdate && !transManager.IsAttachTracking && !transManager.IsRelatedEndAdd)
            {
                ReferentialConstraint constraint = ((AssociationType)RelationMetadata).ReferentialConstraints.Single();
                if (TargetRoleName == constraint.FromRole.Name) // Only do this on the dependent end
                {
                    if (transManager.IsDetaching)
                    {
                        // 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.
                        Debug.Assert(entry != null, "State entry must exist while detaching.");
                        EntityKey foreignKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                        if (foreignKey != null)
                        {
                            stateManager.AddEntryContainingForeignKeyToIndex(foreignKey, entry);
                        }
                    }
                    else if (!ReferenceEquals(stateManager.EntityInvokingFKSetter, WrappedOwner.Entity) && !transManager.IsForeignKeyUpdate)
                    {
                        transManager.BeginForeignKeyUpdate(this);
                        try
                        {
                            bool      unableToNull        = true;
                            bool      canSetModifiedProps = entry != null && (entry.State == EntityState.Modified || entry.State == EntityState.Unchanged);
                            EntitySet dependentEntitySet  = ((AssociationSet)RelationshipSet).AssociationSetEnds[FromEndProperty.Name].EntitySet;
                            StateManagerTypeMetadata dependentTypeMetadata = stateManager.GetOrAddStateManagerTypeMetadata(WrappedOwner.IdentityType, dependentEntitySet);

                            for (int i = 0; i < constraint.FromProperties.Count; i++)
                            {
                                string propertyName               = constraint.ToProperties[i].Name;
                                int    dependentOrdinal           = dependentTypeMetadata.GetOrdinalforOLayerMemberName(propertyName);
                                StateManagerMemberMetadata member = dependentTypeMetadata.Member(dependentOrdinal);

                                // 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.
                                if (member.ClrMetadata.Nullable)
                                {
                                    // Only set the value to null if it is not already null.
                                    if (member.GetValue(WrappedOwner.Entity) != null)
                                    {
                                        WrappedOwner.SetCurrentValue(
                                            WrappedOwner.ObjectStateEntry,
                                            dependentTypeMetadata.Member(dependentOrdinal),
                                            -1,
                                            WrappedOwner.Entity,
                                            null);
                                    }
                                    else
                                    {
                                        // 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.
                                        if (canSetModifiedProps && WrappedOwner.ObjectStateEntry.OriginalValues.GetValue(dependentOrdinal) != null)
                                        {
                                            entry.SetModifiedProperty(propertyName);
                                        }
                                    }
                                    unableToNull = false;
                                }
                                else if (canSetModifiedProps)
                                {
                                    entry.SetModifiedProperty(propertyName);
                                }
                            }
                            if (unableToNull)
                            {
                                // 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
                                if (entry != null)
                                {
                                    //The CachedForeignKey may be null if we are putting
                                    //back a Conceptual Null as part of roll back
                                    EntityKey realKey = CachedForeignKey;
                                    if (realKey == null)
                                    {
                                        realKey = ForeignKeyFactory.CreateKeyFromForeignKeyValues(entry, this);
                                    }

                                    // 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.
                                    if (realKey != null)
                                    {
                                        SetCachedForeignKey(ForeignKeyFactory.CreateConceptualNullKey(realKey), entry);
                                        stateManager.RememberEntryWithConceptualNull(entry);
                                    }
                                }
                            }
                            else
                            {
                                SetCachedForeignKey(null, entry);
                            }
                        }
                        finally
                        {
                            transManager.EndForeignKeyUpdate();
                        }
                    }
                }
            }
        }
Beispiel #12
0
        internal bool NavigationPropertyIsNullOrMissing()
        {
            Debug.Assert(RelationshipNavigation != null, "null RelationshipNavigation");

            return(!TargetAccessor.HasProperty || WrappedOwner.GetNavigationPropertyValue(this) == null);
        }