Code:
/ 4.0 / 4.0 / untmp / 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(IEnumerableentities) { 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(Listcollection, 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) { ListwrappedRelatedEntities = 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
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RootBrowserWindow.cs
- XmlWellformedWriter.cs
- KnownTypes.cs
- AbandonedMutexException.cs
- ManipulationBoundaryFeedbackEventArgs.cs
- VideoDrawing.cs
- XmlSchemaIdentityConstraint.cs
- GlobalizationAssembly.cs
- GregorianCalendar.cs
- ProcessHostConfigUtils.cs
- RangeContentEnumerator.cs
- CfgArc.cs
- Axis.cs
- BaseParagraph.cs
- DrawingContextDrawingContextWalker.cs
- XPathException.cs
- ComponentGuaranteesAttribute.cs
- FontStretchConverter.cs
- XmlSchemaIdentityConstraint.cs
- ButtonField.cs
- Wildcard.cs
- controlskin.cs
- Attributes.cs
- _UriSyntax.cs
- Parser.cs
- TemplateInstanceAttribute.cs
- SiteMap.cs
- UnsafePeerToPeerMethods.cs
- ByteStreamMessage.cs
- EncodingNLS.cs
- ScriptControlDescriptor.cs
- BlurBitmapEffect.cs
- SmtpDigestAuthenticationModule.cs
- ComponentDispatcherThread.cs
- SpellCheck.cs
- _TimerThread.cs
- InternalMappingException.cs
- HttpHandlerActionCollection.cs
- SchemaImporterExtensionElement.cs
- WebPageTraceListener.cs
- AttachmentCollection.cs
- ToolboxItemSnapLineBehavior.cs
- DataServiceRequestOfT.cs
- QilCloneVisitor.cs
- AffineTransform3D.cs
- GroupQuery.cs
- xmlglyphRunInfo.cs
- PageHandlerFactory.cs
- hresults.cs
- DeclarativeExpressionConditionDeclaration.cs
- MSAAWinEventWrap.cs
- ObjectCache.cs
- EdmTypeAttribute.cs
- AstTree.cs
- IPPacketInformation.cs
- Table.cs
- XmlIgnoreAttribute.cs
- QuerySettings.cs
- TileBrush.cs
- TypeSource.cs
- LocatorPart.cs
- ClientSettingsSection.cs
- LogSwitch.cs
- RewritingValidator.cs
- MappingException.cs
- BindingCollectionElement.cs
- WorkflowViewStateService.cs
- FeatureSupport.cs
- OrthographicCamera.cs
- TextBreakpoint.cs
- MouseBinding.cs
- SignerInfo.cs
- NameValueFileSectionHandler.cs
- Single.cs
- WebPartDescriptionCollection.cs
- nulltextnavigator.cs
- XomlCompiler.cs
- SystemKeyConverter.cs
- BinaryReader.cs
- CustomTrackingRecord.cs
- CanonicalFontFamilyReference.cs
- VirtualizingStackPanel.cs
- Stack.cs
- CopyAttributesAction.cs
- ToolTipAutomationPeer.cs
- HttpPostServerProtocol.cs
- ForwardPositionQuery.cs
- TypeSchema.cs
- ImageField.cs
- TCEAdapterGenerator.cs
- TextRangeAdaptor.cs
- MsmqHostedTransportConfiguration.cs
- AncestorChangedEventArgs.cs
- cookieexception.cs
- ColumnResizeUndoUnit.cs
- loginstatus.cs
- ThrowHelper.cs
- ObjectDisposedException.cs
- LogExtentCollection.cs
- KnownBoxes.cs