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
- DictionarySectionHandler.cs
- SEHException.cs
- ErrorFormatter.cs
- QueryConverter.cs
- DropShadowBitmapEffect.cs
- XamlInterfaces.cs
- FieldTemplateFactory.cs
- StylusTouchDevice.cs
- DisposableCollectionWrapper.cs
- BooleanFunctions.cs
- HandlerBase.cs
- DynamicResourceExtension.cs
- AttachedPropertyDescriptor.cs
- Freezable.cs
- __Filters.cs
- RangeBase.cs
- DependentTransaction.cs
- XPathExpr.cs
- Debugger.cs
- HttpListener.cs
- XmlnsPrefixAttribute.cs
- WebPartsPersonalizationAuthorization.cs
- CurrencyManager.cs
- Trace.cs
- BitmapScalingModeValidation.cs
- FormsAuthenticationUserCollection.cs
- AssemblyEvidenceFactory.cs
- UInt64.cs
- DecimalFormatter.cs
- CursorConverter.cs
- AttributeQuery.cs
- UnknownWrapper.cs
- WsdlWriter.cs
- HierarchicalDataSourceControl.cs
- Assert.cs
- NavigationEventArgs.cs
- ControlDesignerState.cs
- XPathAncestorIterator.cs
- WindowsStartMenu.cs
- iisPickupDirectory.cs
- FontWeight.cs
- COM2TypeInfoProcessor.cs
- InvalidOleVariantTypeException.cs
- ToolboxItemFilterAttribute.cs
- ScalarOps.cs
- LocalizableResourceBuilder.cs
- EntityViewGenerator.cs
- Buffer.cs
- HtmlElementEventArgs.cs
- DocumentViewer.cs
- DefaultTextStoreTextComposition.cs
- ScrollChangedEventArgs.cs
- SafeRightsManagementPubHandle.cs
- baseaxisquery.cs
- Literal.cs
- HelpProvider.cs
- Enum.cs
- ProfileInfo.cs
- DataGridViewColumnDesigner.cs
- ZipIOLocalFileDataDescriptor.cs
- XmlAtomicValue.cs
- SystemColors.cs
- ConfigurationProviderException.cs
- Context.cs
- counter.cs
- ToolStripSplitButton.cs
- ControlBindingsCollection.cs
- DoWorkEventArgs.cs
- AutoResizedEvent.cs
- XPathNode.cs
- SurrogateEncoder.cs
- EmptyReadOnlyDictionaryInternal.cs
- SafeUserTokenHandle.cs
- XNameConverter.cs
- UserInitiatedNavigationPermission.cs
- PenLineCapValidation.cs
- WorkflowApplicationCompletedEventArgs.cs
- CurrentChangingEventManager.cs
- CssStyleCollection.cs
- HostingEnvironment.cs
- Dispatcher.cs
- BackgroundWorker.cs
- ObjectStateFormatter.cs
- PrivateFontCollection.cs
- SaveFileDialog.cs
- CompilerCollection.cs
- ClientSideProviderDescription.cs
- SchemaNamespaceManager.cs
- RuntimeArgumentHandle.cs
- DataStorage.cs
- StreamGeometry.cs
- ButtonField.cs
- PaperSource.cs
- ObjectViewFactory.cs
- BitmapVisualManager.cs
- Oid.cs
- DateTimeFormat.cs
- DesignSurfaceManager.cs
- ExpandCollapsePattern.cs
- HttpApplicationFactory.cs