EntityCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / DataClasses / EntityCollection.cs / 1305376 / EntityCollection.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data; 
using System.Data.Common;
using System.Data.Common.CommandTrees; 
using System.Data.Objects.Internal; 
using System.Diagnostics;
using System.Data.Metadata.Edm; 
using System.Runtime.Serialization;
using System.Linq;

namespace System.Data.Objects.DataClasses 
{
    ///  
    /// Collection of entities modelling a particular EDM construct 
    /// which can either be all entiteis of a particular type or
    /// entities participating in a particular relationship. 
    /// 

    [Serializable]
    public sealed class EntityCollection : RelatedEnd, ICollection, IListSource 
        where TEntity : class
    { 
        // ------ 
        // Fields
        // ------ 
        // The following field is serialized.  Adding or removing a serialized field is considered
        // a breaking change.  This includes changing the field type or field name of existing
        // serialized fields. If you need to make this kind of change, it may be possible, but it
        // will require some custom serialization/deserialization code. 
        // Note that this field should no longer be used directly.  Instead, use the _wrappedRelatedEntities
        // field.  This field is retained only for compatability with the serialization format introduced in v1. 
        private HashSet _relatedEntities; 

        [NonSerialized] 
        private CollectionChangeEventHandler _onAssociationChangedforObjectView;

        [NonSerialized]
        private Dictionary _wrappedRelatedEntities; 

        // ------------ 
        // Constructors 
        // ------------
 
        /// 
        /// Creates an empty EntityCollection.
        /// 
        public EntityCollection() 
            : base()
        { 
        } 

        internal EntityCollection(IEntityWrapper wrappedOwner, RelationshipNavigation navigation, IRelationshipFixer relationshipFixer) 
            : base(wrappedOwner, navigation, relationshipFixer)
        {
        }
 
        // ---------
        // Events 
        // --------- 

        ///  
        /// internal Event to notify changes in the collection.
        /// 
        // Dev notes -2
        // following statement is valid on current existing CLR: 
        // lets say Customer is an Entity, Array[Customer] is not Array[Entity]; it is not supported
        // to do the work around we have to use a non-Generic interface/class so we can pass the EntityCollection 
        // around safely (as RelatedEnd) without losing it. 
        // Dev notes -3
        // this event is only used for internal purposes, to make sure views are updated before we fire public AssociationChanged event 
        internal override event CollectionChangeEventHandler AssociationChangedForObjectView {
            add {
                _onAssociationChangedforObjectView += value;
            } 
            remove {
                _onAssociationChangedforObjectView -= value; 
            } 
        }
 

        // ---------
        // Propertites
        // --------- 
        private Dictionary WrappedRelatedEntities
        { 
            get { 
                if (null == _wrappedRelatedEntities)
                { 
                    _wrappedRelatedEntities = new Dictionary();
                }
                return _wrappedRelatedEntities;
            } 
        }
 
        // ---------------------- 
        // ICollection Properties
        // ---------------------- 

        /// 
        /// Count of entities in the collection.
        ///  
        public int Count
        { 
            get 
            {
                DeferredLoad(); 
                return CountInternal;
            }
        }
 
        internal int CountInternal
        { 
            get 
            {
                // count should not cause allocation 
                return ((null != _wrappedRelatedEntities) ? _wrappedRelatedEntities.Count : 0);
            }
        }
 

        ///  
        /// Whether or not the collection is read-only. 
        /// 
        public bool IsReadOnly 
        {
            get
            {
                return false; 
            }
        } 
        // ---------------------- 
        // IListSource  Properties
        // ---------------------- 
        /// 
        ///   IListSource.ContainsListCollection implementation. Always returns true
        /// 
        bool IListSource.ContainsListCollection 
        {
            get 
            { 
                return false; // this means that the IList we return is the one which contains our actual data, it is not a collection
            } 
        }

        // -------
        // Methods 
        // -------
 
        internal override void OnAssociationChanged(CollectionChangeAction collectionChangeAction, object entity) 
        {
            Debug.Assert(!(entity is IEntityWrapper), "Object is an IEntityWrapper instance instead of the raw entity."); 
            if (!_suppressEvents)
            {
                if (_onAssociationChangedforObjectView != null)
                { 
                    _onAssociationChangedforObjectView(this, (new CollectionChangeEventArgs(collectionChangeAction, entity)));
                } 
                if (_onAssociationChanged != null) 
                {
                    _onAssociationChanged(this, (new CollectionChangeEventArgs(collectionChangeAction, entity))); 
                }
            }
        }
 
        // ----------------------
        // IListSource  method 
        // ---------------------- 
        /// 
        ///   IListSource.GetList implementation 
        /// 
        /// 
        ///   IList interface over the data to bind
        ///  
        IList IListSource.GetList()
        { 
            EntityType rootEntityType = null; 
            if (WrappedOwner.Entity != null)
            { 
                EntitySet singleEntitySet = null;

                // if the collection is attached, we can use metadata information; otherwise, it is unavailable
                if (null != this.RelationshipSet) 
                {
                    singleEntitySet = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.ToEndMember.Name].EntitySet; 
                    EntityType associationEndType = (EntityType)((RefType)((AssociationEndMember)this.ToEndMember).TypeUsage.EdmType).ElementType; 
                    EntityType entitySetType = singleEntitySet.ElementType;
 
                    // the type is constrained to be either the entitySet.ElementType or the end member type, whichever is most derived
                    if (associationEndType.IsAssignableFrom(entitySetType))
                    {
                        // entity set exposes a subtype of the association 
                        rootEntityType = entitySetType;
                    } 
                    else 
                    {
                        // use the end type otherwise 
                        rootEntityType = associationEndType;
                    }
                }
            } 

            return ObjectViewFactory.CreateViewForEntityCollection(rootEntityType, this); 
        } 

        ///  
        /// Loads the related entity or entities into the local collection using the supplied MergeOption.
        /// Do merge if collection was already filled
        /// 
        public override void Load(MergeOption mergeOption) 
        {
            CheckOwnerNull(); 
 
            //Pass in null to indicate the CreateSourceQuery method should be used.
            Load((List)null, mergeOption); 
            // do not fire the AssociationChanged event here,
            // once it is fired in one level deeper, (at Internal void Load(IEnumerable)), you dont need to add the event at other
            // API that call (Internal void Load(IEnumerable))
        } 

        ///  
        /// Loads related entities into the local collection. If the collection is already filled 
        /// or partially filled, merges existing entities with the given entities. The given
        /// entities are not assumed to be the complete set of related entities. 
        ///
        /// Owner and all entities passed in must be in Unchanged or Modified state. We allow
        /// deleted elements only when the state manager is already tracking the relationship
        /// instance. 
        /// 
        /// Result of query returning related entities 
        /// Thrown when  is null. 
        /// Thrown when an entity in the given
        /// collection cannot be related via the current relationship end. 
        public void Attach(IEnumerable entities)
        {
            EntityUtil.CheckArgumentNull(entities, "entities");
            CheckOwnerNull(); 
            //
            IList wrappedEntities = new List(); 
            foreach (TEntity entity in entities) 
            {
                wrappedEntities.Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); 
            }
            Attach(wrappedEntities, true);
        }
 
        /// 
        /// Attaches an entity to the EntityCollection. If the EntityCollection is already filled 
        /// or partially filled, this merges the existing entities with the given entity. The given 
        /// entity is not assumed to be the complete set of related entities.
        /// 
        /// Owner and all entities passed in must be in Unchanged or Modified state.
        /// Deleted elements are allowed only when the state manager is already tracking the relationship
        /// instance.
        ///  
        /// The entity to attach to the EntityCollection
        /// Thrown when  is null. 
        /// Thrown when the entity cannot be related via the current relationship end. 
        public void Attach(TEntity entity)
        { 
            EntityUtil.CheckArgumentNull(entity, "entity");
            Attach(new IEntityWrapper[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false);
        }
 
        /// 
        /// Requires: collection is null or contains related entities. 
        /// Loads related entities into the local collection. 
        /// 
        /// If null, retrieves entities from the server through a query; 
        /// otherwise, loads the given collection
        /// 
        internal void Load(List collection, MergeOption mergeOption)
        { 
            // Validate that the Load is possible
            bool hasResults; 
            ObjectQuery sourceQuery = ValidateLoad(mergeOption, "EntityCollection", out hasResults); 

            // we do not want any Add or Remove event to be fired during Merge, we will fire a Refresh event at the end if everything is successful 
            _suppressEvents = true;
            try
            {
                if (collection == null) 
                {
                    Merge(hasResults 
                        ? GetResults(sourceQuery) 
                        : Enumerable.Empty(), mergeOption, true /*setIsLoaded*/);
                } 
                else
                {
                    Merge(collection, mergeOption, true /*setIsLoaded*/);
                } 

            } 
            finally 
            {
                _suppressEvents = false; 
            }
            // fire the AssociationChange with Refresh
            OnAssociationChanged(CollectionChangeAction.Refresh, null);
        } 

        ///  
        /// 
        /// 
        public void Add(TEntity entity) 
        {
            EntityUtil.CheckArgumentNull(entity, "entity");
            Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext));
        } 

        ///  
        /// Add the item to the underlying collection 
        /// 
        ///  
        internal override void DisconnectedAdd(IEntityWrapper wrappedEntity)
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            // Validate that the incoming entity is also detached 
            if (null != wrappedEntity.Context && wrappedEntity.MergeOption != MergeOption.NoTracking)
            { 
                throw EntityUtil.UnableToAddToDisconnectedRelatedEnd(); 
            }
 
            VerifyType(wrappedEntity);

            // Add the entity to local collection without doing any fixup
            AddToCache(wrappedEntity, /* applyConstraints */ false); 
            OnAssociationChanged(CollectionChangeAction.Add, wrappedEntity.Entity);
        } 
 
        /// 
        /// Remove the item from the underlying collection 
        /// 
        /// 
        /// 
        internal override bool DisconnectedRemove(IEntityWrapper wrappedEntity) 
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 
            // Validate that the incoming entity is also detached 
            if (null != wrappedEntity.Context && wrappedEntity.MergeOption != MergeOption.NoTracking)
            { 
                throw EntityUtil.UnableToRemoveFromDisconnectedRelatedEnd();
            }

            // Remove the entity to local collection without doing any fixup 
            bool result = RemoveFromCache(wrappedEntity, /* resetIsLoaded*/ false, /*preserveForeignKey*/ false);
            OnAssociationChanged(CollectionChangeAction.Remove, wrappedEntity.Entity); 
            return result; 
        }
 
        /// 
        ///   Removes an entity from the EntityCollection.  If the owner is
        ///   attached to a context, Remove marks the relationship for deletion and if
        ///   the relationship is composition also marks the entity for deletion. 
        /// 
        ///  
        ///   Entity instance to remove from the EntityCollection 
        /// 
        /// Returns true if the entity was successfully removed, false if the entity was not part of the RelatedEnd. 
        public bool Remove(TEntity entity)
        {
            EntityUtil.CheckArgumentNull(entity, "entity");
            DeferredLoad(); 
            return RemoveInternal(entity);
        } 
 
        internal bool RemoveInternal(TEntity entity)
        { 
            return Remove(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext), /*preserveForeignKey*/false);
        }

        internal override void Include(bool addRelationshipAsUnchanged, bool doAttach) 
        {
            if (null != _wrappedRelatedEntities && null != this.ObjectContext) 
            { 
                List wrappedRelatedEntities = new List(_wrappedRelatedEntities.Values);
                foreach (IEntityWrapper wrappedEntity in wrappedRelatedEntities) 
                {
                    // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends
                    // These should be replaced by the IEntityWrapper that is stored in the context
                    IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(wrappedEntity.Entity, WrappedOwner.Context); 
                    if (identityWrapper != wrappedEntity)
                    { 
                        _wrappedRelatedEntities[(TEntity)identityWrapper.Entity] = identityWrapper; 
                    }
                    IncludeEntity(identityWrapper, addRelationshipAsUnchanged, doAttach); 
                }
            }
        }
 
        internal override void Exclude()
        { 
            if (null != _wrappedRelatedEntities && null != this.ObjectContext) 
            {
                if (!IsForeignKey) 
                {
                    foreach (IEntityWrapper wrappedEntity in _wrappedRelatedEntities.Values)
                    {
                        ExcludeEntity(wrappedEntity); 
                    }
                } 
                else 
                {
                    TransactionManager tm = ObjectContext.ObjectStateManager.TransactionManager; 
                    Debug.Assert(tm.IsAddTracking || tm.IsAttachTracking, "Exclude being called while not part of attach/add rollback--PromotedEntityKeyRefs will be null.");
                    List values = new List(_wrappedRelatedEntities.Values);
                    foreach (IEntityWrapper wrappedEntity in values)
                    { 
                        EntityReference otherEnd = GetOtherEndOfRelationship(wrappedEntity) as EntityReference;
                        Debug.Assert(otherEnd != null, "Other end of FK from a collection should be a reference."); 
                        bool doFullRemove = tm.PopulatedEntityReferences.Contains(otherEnd); 
                        bool doRelatedEndRemove = tm.AlignedEntityReferences.Contains(otherEnd);
                        if (doFullRemove || doRelatedEndRemove) 
                        {
                            // Remove the related ends and mark the relationship as deleted, but don't propagate the changes to the target entity itself
                            otherEnd.Remove(otherEnd.CachedValue,
                                            doFixup: doFullRemove, 
                                            deleteEntity: false,
                                            deleteOwner: false, 
                                            applyReferentialConstraints: false, 
                                            preserveForeignKey: true);
                            // Since this has been processed, remove it from the list 
                            if (doFullRemove)
                            {
                                tm.PopulatedEntityReferences.Remove(otherEnd);
                            } 
                            else
                            { 
                                tm.AlignedEntityReferences.Remove(otherEnd); 
                            }
                        } 
                        else
                        {
                            ExcludeEntity(wrappedEntity);
                        } 
                    }
                } 
            } 
        }
 
        internal override void ClearCollectionOrRef(IEntityWrapper wrappedEntity, RelationshipNavigation navigation, bool doCascadeDelete)
        {
            if (null != _wrappedRelatedEntities)
            { 
                //copy into list because changing collection member is not allowed during enumeration.
                // If possible avoid copying into list. 
                List tempCopy = new List(_wrappedRelatedEntities.Values); 
                foreach (IEntityWrapper wrappedCurrent in tempCopy)
                { 
                    // Following condition checks if we have already visited this graph node. If its true then
                    // we should not do fixup because that would cause circular loop
                    if ((wrappedEntity.Entity == wrappedCurrent.Entity) && (navigation.Equals(RelationshipNavigation)))
                    { 
                        Remove(wrappedCurrent, /*fixup*/false, /*deleteEntity*/false, /*deleteOwner*/false, /*applyReferentialConstraints*/false, /*preserveForeignKey*/false);
                    } 
                    else 
                    {
                        Remove(wrappedCurrent, /*fixup*/true, doCascadeDelete, /*deleteOwner*/false, /*applyReferentialConstraints*/false, /*preserveForeignKey*/false); 
                    }
                }
                Debug.Assert(_wrappedRelatedEntities.Count == 0, "After removing all related entities local collection count should be zero");
            } 
        }
 
        internal override void ClearWrappedValues() 
        {
            if (_wrappedRelatedEntities != null) 
            {
                this._wrappedRelatedEntities.Clear();
            }
            if (_relatedEntities != null) 
            {
                this._relatedEntities.Clear(); 
            } 
        }
 
        /// 
        ///
        /// 
        ///  
        /// 
        /// True if the verify succeeded, False if the Add should no-op 
        internal override bool VerifyEntityForAdd(IEntityWrapper wrappedEntity, bool relationshipAlreadyExists) 
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 
            if (!relationshipAlreadyExists && this.ContainsEntity(wrappedEntity))
            {
                return false;
            } 

            this.VerifyType(wrappedEntity); 
 
            return true;
        } 

        internal override bool CanSetEntityType(IEntityWrapper wrappedEntity)
        {
            return wrappedEntity.Entity is TEntity; 
        }
 
        internal override void VerifyType(IEntityWrapper wrappedEntity) 
        {
            if (!CanSetEntityType(wrappedEntity)) 
            {
                throw EntityUtil.InvalidContainedTypeCollection(wrappedEntity.Entity.GetType().FullName, typeof(TEntity).FullName);
            }
        } 

        ///  
        /// Remove from the RelatedEnd 
        /// 
        ///  
        /// 
        /// 
        internal override bool RemoveFromLocalCache(IEntityWrapper wrappedEntity, bool resetIsLoaded, bool preserveForeignKey)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
 
            if (_wrappedRelatedEntities != null && _wrappedRelatedEntities.Remove((TEntity)wrappedEntity.Entity)) 
            {
                if (resetIsLoaded) 
                {
                    _isLoaded = false;
                }
                return true; 
            }
            return false; 
        } 

        ///  
        /// Remove from the POCO collection
        /// 
        /// 
        ///  
        internal override bool RemoveFromObjectCache(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 

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

            return false; 
        } 

        internal override void RetrieveReferentialConstraintProperties(Dictionary> properties, HashSet visited) 
        {
            // Since there are no RI Constraints which has a collection as a To/Child role,
            // this method is no-op.
        } 

        internal override bool IsEmpty() 
        { 
            return _wrappedRelatedEntities == null || (_wrappedRelatedEntities.Count == 0);
        } 

        internal override void VerifyMultiplicityConstraintsForAdd(bool applyConstraints)
        {
            // no-op 
        }
 
        // Update IsLoaded flag if necessary 
        // This method is called when Clear() was called on the other end of relationship (if the other end is EntityCollection)
        // or when Value property of the other end was set to null (if the other end is EntityReference). 
        // This method is used only when NoTracking option was used.
        internal override void OnRelatedEndClear()
        {
            // If other end of relationship was cleared, it means that this collection is also no longer loaded 
            _isLoaded = false;
        } 
 
        internal override bool ContainsEntity(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            // Using operator 'as' instead of () allows calling ContainsEntity
            // with entity of different type than TEntity.
            TEntity entity = wrappedEntity.Entity as TEntity; 
            return _wrappedRelatedEntities == null ? false : _wrappedRelatedEntities.ContainsKey(entity);
        } 
 
        // -------------------
        // ICollection Methods 
        // -------------------

        /// 
        ///   Get an enumerator for the collection. 
        /// 
        public new IEnumerator GetEnumerator() 
        { 
            DeferredLoad();
            return WrappedRelatedEntities.Keys.GetEnumerator(); 
        }

        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        { 
            DeferredLoad();
            return WrappedRelatedEntities.Keys.GetEnumerator(); 
        } 

        internal override IEnumerable GetInternalEnumerable() 
        {
            return WrappedRelatedEntities.Keys;
        }
 
        internal override IEnumerable GetWrappedEntities()
        { 
            return WrappedRelatedEntities.Values; 
        }
 
        /// 
        /// Removes all entities from the locally cached collection.  Also removes
        /// relationships related to this entities from the ObjectStateManager.
        ///  
        public void Clear()
        { 
            DeferredLoad(); 
            if (WrappedOwner.Entity != null)
            { 
                bool shouldFireEvent = (CountInternal > 0);
                if (null != _wrappedRelatedEntities)
                {
 
                    List affectedEntities = new List(_wrappedRelatedEntities.Values);
 
                    try 
                    {
                        _suppressEvents = true; 

                        foreach (IEntityWrapper wrappedEntity in affectedEntities)
                        {
                            // Remove Entity 
                            Remove(wrappedEntity, false);
 
                            if (UsingNoTracking) 
                            {
                                // The other end of relationship can be the EntityReference or EntityCollection 
                                // If the other end is EntityReference, its IsLoaded property should be set to FALSE
                                RelatedEnd relatedEnd = GetOtherEndOfRelationship(wrappedEntity);
                                relatedEnd.OnRelatedEndClear();
                            } 
                        }
                        Debug.Assert(_wrappedRelatedEntities.Count == 0); 
                    } 
                    finally
                    { 
                        _suppressEvents = false;
                    }

                    if (UsingNoTracking) 
                    {
                        _isLoaded = false; 
                    } 
                }
 
                if (shouldFireEvent)
                {
                    OnAssociationChanged(CollectionChangeAction.Refresh, null);
                } 
            }
            else 
            { 
                // Disconnected Clear should be dispatched to the internal collection
                if (_wrappedRelatedEntities != null) 
                {
                    _wrappedRelatedEntities.Clear();
                }
            } 
        }
 
        ///  
        /// Determine if the collection contains a specific object by reference.
        ///  
        /// true if the collection contains the object by reference;
        /// otherwise, false
        public bool Contains(TEntity entity)
        { 
            DeferredLoad();
            return _wrappedRelatedEntities == null ? false : _wrappedRelatedEntities.ContainsKey(entity); 
        } 

        ///  
        /// Copies the contents of the collection to an array,
        /// starting at a particular array index.
        /// 
        public void CopyTo(TEntity[] array, int arrayIndex) 
        {
            DeferredLoad(); 
            WrappedRelatedEntities.Keys.CopyTo(array, arrayIndex); 
        }
 
        internal override void BulkDeleteAll(List list)
        {
            if (list.Count > 0)
            { 
                _suppressEvents = true;
                try 
                { 
                    foreach (object entity in list)
                    { 
                        // Remove Entity
                        RemoveInternal(entity as TEntity);
                    }
                } 
                finally
                { 
                    _suppressEvents = false; 
                }
                OnAssociationChanged(CollectionChangeAction.Refresh, null); 
            }
        }

        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper) 
        {
            Debug.Assert(this.RelationshipNavigation != null, "null RelationshipNavigation"); 
 
            // If the navigation property doesn't exist (e.g. uni-directional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty) 
            {
                return false;
            }
 
            object value = this.WrappedOwner.GetNavigationPropertyValue(this);
 
            if (value != null) 
            {
                if (!(value is IEnumerable)) 
                {
                    throw new EntityException(System.Data.Entity.Strings.ObjectStateEntry_UnableToEnumerateCollection(
                                            this.TargetAccessor.PropertyName, this.WrappedOwner.Entity.GetType().FullName));
                } 

                // 
                foreach (object o in (value as IEnumerable)) 
                {
                    if (Object.Equals(o, wrapper.Entity)) 
                    {
                        return true;
                    }
                } 
            }
            return false; 
        } 

        internal override void VerifyNavigationPropertyForAdd(IEntityWrapper wrapper) 
        {
            // no-op
        }
 
        // This method is required to maintain compatability with the v1 binary serialization format.
        // In particular, it takes the dictionary of wrapped entities and creates a hash set of 
        // raw entities that will be serialized. 
        // Note that this is only expected to work for non-POCO entities, since serialization of POCO
        // entities will not result in serialization of the RelationshipManager or its related objects. 
        [OnSerializing()]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void OnSerializing(StreamingContext context) 
        {
            if (!(WrappedOwner.Entity is IEntityWithRelationships)) 
            { 
                throw new InvalidOperationException(System.Data.Entity.Strings.RelatedEnd_CannotSerialize("EntityCollection"));
            } 
            _relatedEntities = _wrappedRelatedEntities == null ? null : new HashSet(_wrappedRelatedEntities.Keys);
        }

        // This method is required to maintain compatability with the v1 binary serialization format. 
        // In particular, it takes the _relatedEntities HashSet and recreates the dictionary of wrapped
        // entities from it.  This is because the dictionary is not serialized. 
        // Note that this is only expected to work for non-POCO entities, since serialization of POCO 
        // entities will not result in serialization of the RelationshipManager or its related objects.
        [OnDeserialized()] 
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void OnCollectionDeserialized(StreamingContext context)
        { 
            if (_relatedEntities != null)
            { 
                // We need to call this here so that the hash set will be fully constructed 
                // ready for access.  Normally, this would happen later in the process.
                _relatedEntities.OnDeserialization(null); 
                _wrappedRelatedEntities = new Dictionary();
                foreach (TEntity entity in _relatedEntities)
                {
                    _wrappedRelatedEntities.Add(entity, EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); 
                }
            } 
        } 

        // Identical code is in EntityReference, but this can't be moved to the base class because it relies on the 
        // knowledge of the generic type, and the base class isn't generic
        public ObjectQuery CreateSourceQuery()
        {
            CheckOwnerNull(); 
            bool hasResults;
            return CreateSourceQuery(DefaultMergeOption, out hasResults); 
        } 

        internal override IEnumerable CreateSourceQueryInternal() 
        {
            return CreateSourceQuery();
        }
        //End identical code 

        #region Add 
 
        internal override void AddToLocalCache(IEntityWrapper wrappedEntity, bool applyConstraints)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            WrappedRelatedEntities[(TEntity)wrappedEntity.Entity] = wrappedEntity;
        }
 
        internal override void AddToObjectCache(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 

            // For POCO entities - add the object to the CLR collection 
            if (this.TargetAccessor.HasProperty) // Null if the navigation does not exist in this direction
            {
                this.WrappedOwner.CollectionAdd(this, wrappedEntity.Entity);
            } 
        }
 
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data; 
using System.Data.Common;
using System.Data.Common.CommandTrees; 
using System.Data.Objects.Internal; 
using System.Diagnostics;
using System.Data.Metadata.Edm; 
using System.Runtime.Serialization;
using System.Linq;

namespace System.Data.Objects.DataClasses 
{
    ///  
    /// Collection of entities modelling a particular EDM construct 
    /// which can either be all entiteis of a particular type or
    /// entities participating in a particular relationship. 
    /// 

    [Serializable]
    public sealed class EntityCollection : RelatedEnd, ICollection, IListSource 
        where TEntity : class
    { 
        // ------ 
        // Fields
        // ------ 
        // The following field is serialized.  Adding or removing a serialized field is considered
        // a breaking change.  This includes changing the field type or field name of existing
        // serialized fields. If you need to make this kind of change, it may be possible, but it
        // will require some custom serialization/deserialization code. 
        // Note that this field should no longer be used directly.  Instead, use the _wrappedRelatedEntities
        // field.  This field is retained only for compatability with the serialization format introduced in v1. 
        private HashSet _relatedEntities; 

        [NonSerialized] 
        private CollectionChangeEventHandler _onAssociationChangedforObjectView;

        [NonSerialized]
        private Dictionary _wrappedRelatedEntities; 

        // ------------ 
        // Constructors 
        // ------------
 
        /// 
        /// Creates an empty EntityCollection.
        /// 
        public EntityCollection() 
            : base()
        { 
        } 

        internal EntityCollection(IEntityWrapper wrappedOwner, RelationshipNavigation navigation, IRelationshipFixer relationshipFixer) 
            : base(wrappedOwner, navigation, relationshipFixer)
        {
        }
 
        // ---------
        // Events 
        // --------- 

        ///  
        /// internal Event to notify changes in the collection.
        /// 
        // Dev notes -2
        // following statement is valid on current existing CLR: 
        // lets say Customer is an Entity, Array[Customer] is not Array[Entity]; it is not supported
        // to do the work around we have to use a non-Generic interface/class so we can pass the EntityCollection 
        // around safely (as RelatedEnd) without losing it. 
        // Dev notes -3
        // this event is only used for internal purposes, to make sure views are updated before we fire public AssociationChanged event 
        internal override event CollectionChangeEventHandler AssociationChangedForObjectView {
            add {
                _onAssociationChangedforObjectView += value;
            } 
            remove {
                _onAssociationChangedforObjectView -= value; 
            } 
        }
 

        // ---------
        // Propertites
        // --------- 
        private Dictionary WrappedRelatedEntities
        { 
            get { 
                if (null == _wrappedRelatedEntities)
                { 
                    _wrappedRelatedEntities = new Dictionary();
                }
                return _wrappedRelatedEntities;
            } 
        }
 
        // ---------------------- 
        // ICollection Properties
        // ---------------------- 

        /// 
        /// Count of entities in the collection.
        ///  
        public int Count
        { 
            get 
            {
                DeferredLoad(); 
                return CountInternal;
            }
        }
 
        internal int CountInternal
        { 
            get 
            {
                // count should not cause allocation 
                return ((null != _wrappedRelatedEntities) ? _wrappedRelatedEntities.Count : 0);
            }
        }
 

        ///  
        /// Whether or not the collection is read-only. 
        /// 
        public bool IsReadOnly 
        {
            get
            {
                return false; 
            }
        } 
        // ---------------------- 
        // IListSource  Properties
        // ---------------------- 
        /// 
        ///   IListSource.ContainsListCollection implementation. Always returns true
        /// 
        bool IListSource.ContainsListCollection 
        {
            get 
            { 
                return false; // this means that the IList we return is the one which contains our actual data, it is not a collection
            } 
        }

        // -------
        // Methods 
        // -------
 
        internal override void OnAssociationChanged(CollectionChangeAction collectionChangeAction, object entity) 
        {
            Debug.Assert(!(entity is IEntityWrapper), "Object is an IEntityWrapper instance instead of the raw entity."); 
            if (!_suppressEvents)
            {
                if (_onAssociationChangedforObjectView != null)
                { 
                    _onAssociationChangedforObjectView(this, (new CollectionChangeEventArgs(collectionChangeAction, entity)));
                } 
                if (_onAssociationChanged != null) 
                {
                    _onAssociationChanged(this, (new CollectionChangeEventArgs(collectionChangeAction, entity))); 
                }
            }
        }
 
        // ----------------------
        // IListSource  method 
        // ---------------------- 
        /// 
        ///   IListSource.GetList implementation 
        /// 
        /// 
        ///   IList interface over the data to bind
        ///  
        IList IListSource.GetList()
        { 
            EntityType rootEntityType = null; 
            if (WrappedOwner.Entity != null)
            { 
                EntitySet singleEntitySet = null;

                // if the collection is attached, we can use metadata information; otherwise, it is unavailable
                if (null != this.RelationshipSet) 
                {
                    singleEntitySet = ((AssociationSet)this.RelationshipSet).AssociationSetEnds[this.ToEndMember.Name].EntitySet; 
                    EntityType associationEndType = (EntityType)((RefType)((AssociationEndMember)this.ToEndMember).TypeUsage.EdmType).ElementType; 
                    EntityType entitySetType = singleEntitySet.ElementType;
 
                    // the type is constrained to be either the entitySet.ElementType or the end member type, whichever is most derived
                    if (associationEndType.IsAssignableFrom(entitySetType))
                    {
                        // entity set exposes a subtype of the association 
                        rootEntityType = entitySetType;
                    } 
                    else 
                    {
                        // use the end type otherwise 
                        rootEntityType = associationEndType;
                    }
                }
            } 

            return ObjectViewFactory.CreateViewForEntityCollection(rootEntityType, this); 
        } 

        ///  
        /// Loads the related entity or entities into the local collection using the supplied MergeOption.
        /// Do merge if collection was already filled
        /// 
        public override void Load(MergeOption mergeOption) 
        {
            CheckOwnerNull(); 
 
            //Pass in null to indicate the CreateSourceQuery method should be used.
            Load((List)null, mergeOption); 
            // do not fire the AssociationChanged event here,
            // once it is fired in one level deeper, (at Internal void Load(IEnumerable)), you dont need to add the event at other
            // API that call (Internal void Load(IEnumerable))
        } 

        ///  
        /// Loads related entities into the local collection. If the collection is already filled 
        /// or partially filled, merges existing entities with the given entities. The given
        /// entities are not assumed to be the complete set of related entities. 
        ///
        /// Owner and all entities passed in must be in Unchanged or Modified state. We allow
        /// deleted elements only when the state manager is already tracking the relationship
        /// instance. 
        /// 
        /// Result of query returning related entities 
        /// Thrown when  is null. 
        /// Thrown when an entity in the given
        /// collection cannot be related via the current relationship end. 
        public void Attach(IEnumerable entities)
        {
            EntityUtil.CheckArgumentNull(entities, "entities");
            CheckOwnerNull(); 
            //
            IList wrappedEntities = new List(); 
            foreach (TEntity entity in entities) 
            {
                wrappedEntities.Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); 
            }
            Attach(wrappedEntities, true);
        }
 
        /// 
        /// Attaches an entity to the EntityCollection. If the EntityCollection is already filled 
        /// or partially filled, this merges the existing entities with the given entity. The given 
        /// entity is not assumed to be the complete set of related entities.
        /// 
        /// Owner and all entities passed in must be in Unchanged or Modified state.
        /// Deleted elements are allowed only when the state manager is already tracking the relationship
        /// instance.
        ///  
        /// The entity to attach to the EntityCollection
        /// Thrown when  is null. 
        /// Thrown when the entity cannot be related via the current relationship end. 
        public void Attach(TEntity entity)
        { 
            EntityUtil.CheckArgumentNull(entity, "entity");
            Attach(new IEntityWrapper[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false);
        }
 
        /// 
        /// Requires: collection is null or contains related entities. 
        /// Loads related entities into the local collection. 
        /// 
        /// If null, retrieves entities from the server through a query; 
        /// otherwise, loads the given collection
        /// 
        internal void Load(List collection, MergeOption mergeOption)
        { 
            // Validate that the Load is possible
            bool hasResults; 
            ObjectQuery sourceQuery = ValidateLoad(mergeOption, "EntityCollection", out hasResults); 

            // we do not want any Add or Remove event to be fired during Merge, we will fire a Refresh event at the end if everything is successful 
            _suppressEvents = true;
            try
            {
                if (collection == null) 
                {
                    Merge(hasResults 
                        ? GetResults(sourceQuery) 
                        : Enumerable.Empty(), mergeOption, true /*setIsLoaded*/);
                } 
                else
                {
                    Merge(collection, mergeOption, true /*setIsLoaded*/);
                } 

            } 
            finally 
            {
                _suppressEvents = false; 
            }
            // fire the AssociationChange with Refresh
            OnAssociationChanged(CollectionChangeAction.Refresh, null);
        } 

        ///  
        /// 
        /// 
        public void Add(TEntity entity) 
        {
            EntityUtil.CheckArgumentNull(entity, "entity");
            Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext));
        } 

        ///  
        /// Add the item to the underlying collection 
        /// 
        ///  
        internal override void DisconnectedAdd(IEntityWrapper wrappedEntity)
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            // Validate that the incoming entity is also detached 
            if (null != wrappedEntity.Context && wrappedEntity.MergeOption != MergeOption.NoTracking)
            { 
                throw EntityUtil.UnableToAddToDisconnectedRelatedEnd(); 
            }
 
            VerifyType(wrappedEntity);

            // Add the entity to local collection without doing any fixup
            AddToCache(wrappedEntity, /* applyConstraints */ false); 
            OnAssociationChanged(CollectionChangeAction.Add, wrappedEntity.Entity);
        } 
 
        /// 
        /// Remove the item from the underlying collection 
        /// 
        /// 
        /// 
        internal override bool DisconnectedRemove(IEntityWrapper wrappedEntity) 
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 
            // Validate that the incoming entity is also detached 
            if (null != wrappedEntity.Context && wrappedEntity.MergeOption != MergeOption.NoTracking)
            { 
                throw EntityUtil.UnableToRemoveFromDisconnectedRelatedEnd();
            }

            // Remove the entity to local collection without doing any fixup 
            bool result = RemoveFromCache(wrappedEntity, /* resetIsLoaded*/ false, /*preserveForeignKey*/ false);
            OnAssociationChanged(CollectionChangeAction.Remove, wrappedEntity.Entity); 
            return result; 
        }
 
        /// 
        ///   Removes an entity from the EntityCollection.  If the owner is
        ///   attached to a context, Remove marks the relationship for deletion and if
        ///   the relationship is composition also marks the entity for deletion. 
        /// 
        ///  
        ///   Entity instance to remove from the EntityCollection 
        /// 
        /// Returns true if the entity was successfully removed, false if the entity was not part of the RelatedEnd. 
        public bool Remove(TEntity entity)
        {
            EntityUtil.CheckArgumentNull(entity, "entity");
            DeferredLoad(); 
            return RemoveInternal(entity);
        } 
 
        internal bool RemoveInternal(TEntity entity)
        { 
            return Remove(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext), /*preserveForeignKey*/false);
        }

        internal override void Include(bool addRelationshipAsUnchanged, bool doAttach) 
        {
            if (null != _wrappedRelatedEntities && null != this.ObjectContext) 
            { 
                List wrappedRelatedEntities = new List(_wrappedRelatedEntities.Values);
                foreach (IEntityWrapper wrappedEntity in wrappedRelatedEntities) 
                {
                    // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends
                    // These should be replaced by the IEntityWrapper that is stored in the context
                    IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(wrappedEntity.Entity, WrappedOwner.Context); 
                    if (identityWrapper != wrappedEntity)
                    { 
                        _wrappedRelatedEntities[(TEntity)identityWrapper.Entity] = identityWrapper; 
                    }
                    IncludeEntity(identityWrapper, addRelationshipAsUnchanged, doAttach); 
                }
            }
        }
 
        internal override void Exclude()
        { 
            if (null != _wrappedRelatedEntities && null != this.ObjectContext) 
            {
                if (!IsForeignKey) 
                {
                    foreach (IEntityWrapper wrappedEntity in _wrappedRelatedEntities.Values)
                    {
                        ExcludeEntity(wrappedEntity); 
                    }
                } 
                else 
                {
                    TransactionManager tm = ObjectContext.ObjectStateManager.TransactionManager; 
                    Debug.Assert(tm.IsAddTracking || tm.IsAttachTracking, "Exclude being called while not part of attach/add rollback--PromotedEntityKeyRefs will be null.");
                    List values = new List(_wrappedRelatedEntities.Values);
                    foreach (IEntityWrapper wrappedEntity in values)
                    { 
                        EntityReference otherEnd = GetOtherEndOfRelationship(wrappedEntity) as EntityReference;
                        Debug.Assert(otherEnd != null, "Other end of FK from a collection should be a reference."); 
                        bool doFullRemove = tm.PopulatedEntityReferences.Contains(otherEnd); 
                        bool doRelatedEndRemove = tm.AlignedEntityReferences.Contains(otherEnd);
                        if (doFullRemove || doRelatedEndRemove) 
                        {
                            // Remove the related ends and mark the relationship as deleted, but don't propagate the changes to the target entity itself
                            otherEnd.Remove(otherEnd.CachedValue,
                                            doFixup: doFullRemove, 
                                            deleteEntity: false,
                                            deleteOwner: false, 
                                            applyReferentialConstraints: false, 
                                            preserveForeignKey: true);
                            // Since this has been processed, remove it from the list 
                            if (doFullRemove)
                            {
                                tm.PopulatedEntityReferences.Remove(otherEnd);
                            } 
                            else
                            { 
                                tm.AlignedEntityReferences.Remove(otherEnd); 
                            }
                        } 
                        else
                        {
                            ExcludeEntity(wrappedEntity);
                        } 
                    }
                } 
            } 
        }
 
        internal override void ClearCollectionOrRef(IEntityWrapper wrappedEntity, RelationshipNavigation navigation, bool doCascadeDelete)
        {
            if (null != _wrappedRelatedEntities)
            { 
                //copy into list because changing collection member is not allowed during enumeration.
                // If possible avoid copying into list. 
                List tempCopy = new List(_wrappedRelatedEntities.Values); 
                foreach (IEntityWrapper wrappedCurrent in tempCopy)
                { 
                    // Following condition checks if we have already visited this graph node. If its true then
                    // we should not do fixup because that would cause circular loop
                    if ((wrappedEntity.Entity == wrappedCurrent.Entity) && (navigation.Equals(RelationshipNavigation)))
                    { 
                        Remove(wrappedCurrent, /*fixup*/false, /*deleteEntity*/false, /*deleteOwner*/false, /*applyReferentialConstraints*/false, /*preserveForeignKey*/false);
                    } 
                    else 
                    {
                        Remove(wrappedCurrent, /*fixup*/true, doCascadeDelete, /*deleteOwner*/false, /*applyReferentialConstraints*/false, /*preserveForeignKey*/false); 
                    }
                }
                Debug.Assert(_wrappedRelatedEntities.Count == 0, "After removing all related entities local collection count should be zero");
            } 
        }
 
        internal override void ClearWrappedValues() 
        {
            if (_wrappedRelatedEntities != null) 
            {
                this._wrappedRelatedEntities.Clear();
            }
            if (_relatedEntities != null) 
            {
                this._relatedEntities.Clear(); 
            } 
        }
 
        /// 
        ///
        /// 
        ///  
        /// 
        /// True if the verify succeeded, False if the Add should no-op 
        internal override bool VerifyEntityForAdd(IEntityWrapper wrappedEntity, bool relationshipAlreadyExists) 
        {
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 
            if (!relationshipAlreadyExists && this.ContainsEntity(wrappedEntity))
            {
                return false;
            } 

            this.VerifyType(wrappedEntity); 
 
            return true;
        } 

        internal override bool CanSetEntityType(IEntityWrapper wrappedEntity)
        {
            return wrappedEntity.Entity is TEntity; 
        }
 
        internal override void VerifyType(IEntityWrapper wrappedEntity) 
        {
            if (!CanSetEntityType(wrappedEntity)) 
            {
                throw EntityUtil.InvalidContainedTypeCollection(wrappedEntity.Entity.GetType().FullName, typeof(TEntity).FullName);
            }
        } 

        ///  
        /// Remove from the RelatedEnd 
        /// 
        ///  
        /// 
        /// 
        internal override bool RemoveFromLocalCache(IEntityWrapper wrappedEntity, bool resetIsLoaded, bool preserveForeignKey)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
 
            if (_wrappedRelatedEntities != null && _wrappedRelatedEntities.Remove((TEntity)wrappedEntity.Entity)) 
            {
                if (resetIsLoaded) 
                {
                    _isLoaded = false;
                }
                return true; 
            }
            return false; 
        } 

        ///  
        /// Remove from the POCO collection
        /// 
        /// 
        ///  
        internal override bool RemoveFromObjectCache(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 

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

            return false; 
        } 

        internal override void RetrieveReferentialConstraintProperties(Dictionary> properties, HashSet visited) 
        {
            // Since there are no RI Constraints which has a collection as a To/Child role,
            // this method is no-op.
        } 

        internal override bool IsEmpty() 
        { 
            return _wrappedRelatedEntities == null || (_wrappedRelatedEntities.Count == 0);
        } 

        internal override void VerifyMultiplicityConstraintsForAdd(bool applyConstraints)
        {
            // no-op 
        }
 
        // Update IsLoaded flag if necessary 
        // This method is called when Clear() was called on the other end of relationship (if the other end is EntityCollection)
        // or when Value property of the other end was set to null (if the other end is EntityReference). 
        // This method is used only when NoTracking option was used.
        internal override void OnRelatedEndClear()
        {
            // If other end of relationship was cleared, it means that this collection is also no longer loaded 
            _isLoaded = false;
        } 
 
        internal override bool ContainsEntity(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            // Using operator 'as' instead of () allows calling ContainsEntity
            // with entity of different type than TEntity.
            TEntity entity = wrappedEntity.Entity as TEntity; 
            return _wrappedRelatedEntities == null ? false : _wrappedRelatedEntities.ContainsKey(entity);
        } 
 
        // -------------------
        // ICollection Methods 
        // -------------------

        /// 
        ///   Get an enumerator for the collection. 
        /// 
        public new IEnumerator GetEnumerator() 
        { 
            DeferredLoad();
            return WrappedRelatedEntities.Keys.GetEnumerator(); 
        }

        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        { 
            DeferredLoad();
            return WrappedRelatedEntities.Keys.GetEnumerator(); 
        } 

        internal override IEnumerable GetInternalEnumerable() 
        {
            return WrappedRelatedEntities.Keys;
        }
 
        internal override IEnumerable GetWrappedEntities()
        { 
            return WrappedRelatedEntities.Values; 
        }
 
        /// 
        /// Removes all entities from the locally cached collection.  Also removes
        /// relationships related to this entities from the ObjectStateManager.
        ///  
        public void Clear()
        { 
            DeferredLoad(); 
            if (WrappedOwner.Entity != null)
            { 
                bool shouldFireEvent = (CountInternal > 0);
                if (null != _wrappedRelatedEntities)
                {
 
                    List affectedEntities = new List(_wrappedRelatedEntities.Values);
 
                    try 
                    {
                        _suppressEvents = true; 

                        foreach (IEntityWrapper wrappedEntity in affectedEntities)
                        {
                            // Remove Entity 
                            Remove(wrappedEntity, false);
 
                            if (UsingNoTracking) 
                            {
                                // The other end of relationship can be the EntityReference or EntityCollection 
                                // If the other end is EntityReference, its IsLoaded property should be set to FALSE
                                RelatedEnd relatedEnd = GetOtherEndOfRelationship(wrappedEntity);
                                relatedEnd.OnRelatedEndClear();
                            } 
                        }
                        Debug.Assert(_wrappedRelatedEntities.Count == 0); 
                    } 
                    finally
                    { 
                        _suppressEvents = false;
                    }

                    if (UsingNoTracking) 
                    {
                        _isLoaded = false; 
                    } 
                }
 
                if (shouldFireEvent)
                {
                    OnAssociationChanged(CollectionChangeAction.Refresh, null);
                } 
            }
            else 
            { 
                // Disconnected Clear should be dispatched to the internal collection
                if (_wrappedRelatedEntities != null) 
                {
                    _wrappedRelatedEntities.Clear();
                }
            } 
        }
 
        ///  
        /// Determine if the collection contains a specific object by reference.
        ///  
        /// true if the collection contains the object by reference;
        /// otherwise, false
        public bool Contains(TEntity entity)
        { 
            DeferredLoad();
            return _wrappedRelatedEntities == null ? false : _wrappedRelatedEntities.ContainsKey(entity); 
        } 

        ///  
        /// Copies the contents of the collection to an array,
        /// starting at a particular array index.
        /// 
        public void CopyTo(TEntity[] array, int arrayIndex) 
        {
            DeferredLoad(); 
            WrappedRelatedEntities.Keys.CopyTo(array, arrayIndex); 
        }
 
        internal override void BulkDeleteAll(List list)
        {
            if (list.Count > 0)
            { 
                _suppressEvents = true;
                try 
                { 
                    foreach (object entity in list)
                    { 
                        // Remove Entity
                        RemoveInternal(entity as TEntity);
                    }
                } 
                finally
                { 
                    _suppressEvents = false; 
                }
                OnAssociationChanged(CollectionChangeAction.Refresh, null); 
            }
        }

        internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper) 
        {
            Debug.Assert(this.RelationshipNavigation != null, "null RelationshipNavigation"); 
 
            // If the navigation property doesn't exist (e.g. uni-directional prop), then it can't contain the entity.
            if (!TargetAccessor.HasProperty) 
            {
                return false;
            }
 
            object value = this.WrappedOwner.GetNavigationPropertyValue(this);
 
            if (value != null) 
            {
                if (!(value is IEnumerable)) 
                {
                    throw new EntityException(System.Data.Entity.Strings.ObjectStateEntry_UnableToEnumerateCollection(
                                            this.TargetAccessor.PropertyName, this.WrappedOwner.Entity.GetType().FullName));
                } 

                // 
                foreach (object o in (value as IEnumerable)) 
                {
                    if (Object.Equals(o, wrapper.Entity)) 
                    {
                        return true;
                    }
                } 
            }
            return false; 
        } 

        internal override void VerifyNavigationPropertyForAdd(IEntityWrapper wrapper) 
        {
            // no-op
        }
 
        // This method is required to maintain compatability with the v1 binary serialization format.
        // In particular, it takes the dictionary of wrapped entities and creates a hash set of 
        // raw entities that will be serialized. 
        // Note that this is only expected to work for non-POCO entities, since serialization of POCO
        // entities will not result in serialization of the RelationshipManager or its related objects. 
        [OnSerializing()]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void OnSerializing(StreamingContext context) 
        {
            if (!(WrappedOwner.Entity is IEntityWithRelationships)) 
            { 
                throw new InvalidOperationException(System.Data.Entity.Strings.RelatedEnd_CannotSerialize("EntityCollection"));
            } 
            _relatedEntities = _wrappedRelatedEntities == null ? null : new HashSet(_wrappedRelatedEntities.Keys);
        }

        // This method is required to maintain compatability with the v1 binary serialization format. 
        // In particular, it takes the _relatedEntities HashSet and recreates the dictionary of wrapped
        // entities from it.  This is because the dictionary is not serialized. 
        // Note that this is only expected to work for non-POCO entities, since serialization of POCO 
        // entities will not result in serialization of the RelationshipManager or its related objects.
        [OnDeserialized()] 
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void OnCollectionDeserialized(StreamingContext context)
        { 
            if (_relatedEntities != null)
            { 
                // We need to call this here so that the hash set will be fully constructed 
                // ready for access.  Normally, this would happen later in the process.
                _relatedEntities.OnDeserialization(null); 
                _wrappedRelatedEntities = new Dictionary();
                foreach (TEntity entity in _relatedEntities)
                {
                    _wrappedRelatedEntities.Add(entity, EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); 
                }
            } 
        } 

        // Identical code is in EntityReference, but this can't be moved to the base class because it relies on the 
        // knowledge of the generic type, and the base class isn't generic
        public ObjectQuery CreateSourceQuery()
        {
            CheckOwnerNull(); 
            bool hasResults;
            return CreateSourceQuery(DefaultMergeOption, out hasResults); 
        } 

        internal override IEnumerable CreateSourceQueryInternal() 
        {
            return CreateSourceQuery();
        }
        //End identical code 

        #region Add 
 
        internal override void AddToLocalCache(IEntityWrapper wrappedEntity, bool applyConstraints)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null.");
            WrappedRelatedEntities[(TEntity)wrappedEntity.Entity] = wrappedEntity;
        }
 
        internal override void AddToObjectCache(IEntityWrapper wrappedEntity)
        { 
            Debug.Assert(wrappedEntity != null, "IEntityWrapper instance is null."); 

            // For POCO entities - add the object to the CLR collection 
            if (this.TargetAccessor.HasProperty) // Null if the navigation does not exist in this direction
            {
                this.WrappedOwner.CollectionAdd(this, wrappedEntity.Entity);
            } 
        }
 
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK