internal void HandleAddEntity(object source, string sourceProperty, string sourceEntitySet, ICollection collection, object target, string targetEntitySet) { if (!this.Context.ApplyingChanges && ((source == null) || !this.IsDetachedOrDeletedFromContext(source))) { EntityDescriptor entityDescriptor = this.Context.GetEntityDescriptor(target); if ((!this.AttachBehavior && ((entityDescriptor == null) || (((source != null) && !this.IsContextTrackingLink(source, sourceProperty, target)) && (entityDescriptor.State != EntityStates.Deleted)))) && (this.CollectionChanged != null)) { EntityCollectionChangedParams arg = new EntityCollectionChangedParams(this.Context, source, sourceProperty, sourceEntitySet, collection, target, targetEntitySet, NotifyCollectionChangedAction.Add); if (this.CollectionChanged(arg)) { return; } } if ((source != null) && this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } entityDescriptor = this.Context.GetEntityDescriptor(target); if (source != null) { if (!this.AttachBehavior) { if (entityDescriptor == null) { this.Context.AddRelatedObject(source, sourceProperty, target); } else if ((entityDescriptor.State != EntityStates.Deleted) && !this.IsContextTrackingLink(source, sourceProperty, target)) { this.Context.AddLink(source, sourceProperty, target); } } else if (entityDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); this.Context.AttachTo(targetEntitySet, target); this.Context.AttachLink(source, sourceProperty, target); } else if ((entityDescriptor.State != EntityStates.Deleted) && !this.IsContextTrackingLink(source, sourceProperty, target)) { this.Context.AttachLink(source, sourceProperty, target); } } else if (entityDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { this.Context.AttachTo(targetEntitySet, target); } else { this.Context.AddObject(targetEntitySet, target); } } } }
internal void HandleUpdateEntityReference(object source, string sourceProperty, string sourceEntitySet, object target, string targetEntitySet) { if (!this.Context.ApplyingChanges && !this.IsDetachedOrDeletedFromContext(source)) { EntityDescriptor entityDescriptor = (target != null) ? this.Context.GetEntityDescriptor(target) : null; if ((!this.AttachBehavior && ((entityDescriptor == null) || !this.IsContextTrackingLink(source, sourceProperty, target))) && (this.EntityChanged != null)) { EntityChangedParams arg = new EntityChangedParams(this.Context, source, sourceProperty, target, sourceEntitySet, targetEntitySet); if (this.EntityChanged(arg)) { return; } } if (this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } entityDescriptor = (target != null) ? this.Context.GetEntityDescriptor(target) : null; if (target != null) { if (entityDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { this.Context.AttachTo(targetEntitySet, target); } else { this.Context.AddObject(targetEntitySet, target); } entityDescriptor = this.Context.GetEntityDescriptor(target); } if (!this.IsContextTrackingLink(source, sourceProperty, target)) { if (!this.AttachBehavior) { this.Context.SetLink(source, sourceProperty, target); } else if (entityDescriptor.State != EntityStates.Deleted) { this.Context.AttachLink(source, sourceProperty, target); } } } else { this.Context.SetLink(source, sourceProperty, null); } } }
internal void HandleUpdateEntityReference( object source, string sourceProperty, string sourceEntitySet, object target, string targetEntitySet) { if (this.Context.ApplyingChanges) { return; } Debug.Assert(source != null, "source can not be null for update operations."); Debug.Assert(BindingEntityInfo.IsEntityType(source.GetType()), "source must be an entity with keys."); Debug.Assert(!String.IsNullOrEmpty(sourceProperty), "sourceProperty must be a non-empty string for update operations."); Debug.Assert(!String.IsNullOrEmpty(sourceEntitySet), "sourceEntitySet must be non-empty string for update operation."); if (this.IsDetachedOrDeletedFromContext(source)) { return; } EntityDescriptor targetDescriptor = target != null?this.Context.GetEntityDescriptor(target) : null; bool contextOperationRequired = !this.AttachBehavior && (targetDescriptor == null || !this.IsContextTrackingLink(source, sourceProperty, target)); if (contextOperationRequired) { if (this.EntityChanged != null) { EntityChangedParams args = new EntityChangedParams( this.Context, source, sourceProperty, target, sourceEntitySet, targetEntitySet); if (this.EntityChanged(args)) { return; } } } if (this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } targetDescriptor = target != null?this.Context.GetEntityDescriptor(target) : null; if (target != null) { if (targetDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { this.Context.AttachTo(targetEntitySet, target); } else { this.Context.AddObject(targetEntitySet, target); } targetDescriptor = this.Context.GetEntityDescriptor(target); } if (!this.IsContextTrackingLink(source, sourceProperty, target)) { if (this.AttachBehavior) { if (targetDescriptor.State != EntityStates.Deleted) { this.Context.AttachLink(source, sourceProperty, target); } } else { this.Context.SetLink(source, sourceProperty, target); } } } else { Debug.Assert(!this.AttachBehavior, "During attach operations we must never perform operations for null values."); this.Context.SetLink(source, sourceProperty, null); } }
internal void HandleAddEntity( object source, string sourceProperty, string sourceEntitySet, ICollection collection, object target, string targetEntitySet) { if (this.Context.ApplyingChanges) { return; } Debug.Assert( (source == null && sourceProperty == null) || (source != null && !String.IsNullOrEmpty(sourceProperty)), "source and sourceProperty should either both be present or both be absent."); Debug.Assert(target != null, "target must be provided by the caller."); Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "target must be an entity type."); if (source != null && this.IsDetachedOrDeletedFromContext(source)) { return; } EntityDescriptor targetDescriptor = this.Context.GetEntityDescriptor(target); bool contextOperationRequired = !this.AttachBehavior && (targetDescriptor == null || (source != null && !this.IsContextTrackingLink(source, sourceProperty, target) && targetDescriptor.State != EntityStates.Deleted)); if (contextOperationRequired) { if (this.CollectionChanged != null) { EntityCollectionChangedParams args = new EntityCollectionChangedParams( this.Context, source, sourceProperty, sourceEntitySet, collection, target, targetEntitySet, NotifyCollectionChangedAction.Add); if (this.CollectionChanged(args)) { return; } } } if (source != null && this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } targetDescriptor = this.Context.GetEntityDescriptor(target); if (source != null) { if (this.AttachBehavior) { if (targetDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); this.Context.AttachTo(targetEntitySet, target); this.Context.AttachLink(source, sourceProperty, target); } else if (targetDescriptor.State != EntityStates.Deleted && !this.IsContextTrackingLink(source, sourceProperty, target)) { this.Context.AttachLink(source, sourceProperty, target); } } else { if (targetDescriptor == null) { this.Context.AddRelatedObject(source, sourceProperty, target); } else if (targetDescriptor.State != EntityStates.Deleted && !this.IsContextTrackingLink(source, sourceProperty, target)) { this.Context.AddLink(source, sourceProperty, target); } } } else if (targetDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { this.Context.AttachTo(targetEntitySet, target); } else { this.Context.AddObject(targetEntitySet, target); } } }
public bool AddCollection( object source, string sourceProperty, object collection, string collectionEntitySet) { Debug.Assert(collection != null, "'collection' can not be null"); Debug.Assert( BindingEntityInfo.IsDataServiceCollection(collection.GetType()), "Argument 'collection' must be an DataServiceCollection<T> of entity type T"); if (this.graph.ExistsVertex(collection)) { return(false); } Vertex collectionVertex = this.graph.AddVertex(collection); collectionVertex.IsCollection = true; collectionVertex.EntitySet = collectionEntitySet; ICollection collectionItf = collection as ICollection; if (source != null) { collectionVertex.Parent = this.graph.LookupVertex(source); collectionVertex.ParentProperty = sourceProperty; this.graph.AddEdge(source, collection, sourceProperty); Type entityType = BindingUtils.GetCollectionEntityType(collection.GetType()); Debug.Assert(entityType != null, "Collection must at least be inherited from DataServiceCollection<T>"); if (!typeof(INotifyPropertyChanged).IsAssignableFrom(entityType)) { throw new InvalidOperationException(Strings.DataBinding_NotifyPropertyChangedNotImpl(entityType)); } typeof(BindingGraph) .GetMethod("SetObserver", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(entityType) .Invoke(this, new object[] { collectionItf }); } else { this.graph.Root = collectionVertex; } Debug.Assert( collectionVertex.Parent != null || collectionVertex.IsRootCollection, "If parent is null, then collectionVertex should be a root collection"); this.AttachCollectionNotification(collection); foreach (var item in collectionItf) { this.AddEntity( source, sourceProperty, item, collectionEntitySet, collection); } return(true); }
/// <summary>Handle changes to navigation properties of a tracked entity. Perform operations on context to reflect the changes.</summary> /// <param name="source">The source object that reference the target object through a navigation property.</param> /// <param name="sourceProperty">The navigation property in the source object that reference the target object.</param> /// <param name="sourceEntitySet">The entity set of the source object.</param> /// <param name="target">The target entity.</param> /// <param name="targetEntitySet">The entity set name of the target object.</param> internal void HandleUpdateEntityReference( object source, string sourceProperty, string sourceEntitySet, object target, string targetEntitySet) { if (this.Context.ApplyingChanges) { return; } Debug.Assert(source != null, "source can not be null for update operations."); Debug.Assert(BindingEntityInfo.IsEntityType(source.GetType()), "source must be an entity with keys."); Debug.Assert(!String.IsNullOrEmpty(sourceProperty), "sourceProperty must be a non-empty string for update operations."); Debug.Assert(!String.IsNullOrEmpty(sourceEntitySet), "sourceEntitySet must be non-empty string for update operation."); // Do not handle update for detached and deleted entities. if (this.IsDetachedOrDeletedFromContext(source)) { return; } // Do we need an operation on context to handle the Update operation. EntityDescriptor targetDescriptor = target != null?this.Context.GetEntityDescriptor(target) : null; // Following are the conditions where context operation is required: // 1. Not a call to Load or constructions i.e. we have Add behavior and not Attach behavior // 2. Target entity is not being tracked // 3. Target is being tracked but there is no link between the source and target entity bool contextOperationRequired = !this.AttachBehavior && (targetDescriptor == null || !this.IsContextTrackingLink(source, sourceProperty, target)); if (contextOperationRequired) { // First give the user code a chance to handle Update link operation. if (this.EntityChanged != null) { EntityChangedParams args = new EntityChangedParams( this.Context, source, sourceProperty, target, sourceEntitySet, targetEntitySet); if (this.EntityChanged(args)) { return; } } } // The user callback code could detach the source. if (this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } // Default implementation. targetDescriptor = target != null?this.Context.GetEntityDescriptor(target) : null; if (target != null) { if (targetDescriptor == null) { // If the entity set name is not known, then we must throw since we need to know the // entity set in order to add/attach the referenced object to it's entity set. BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { this.Context.AttachTo(targetEntitySet, target); } else { this.Context.AddObject(targetEntitySet, target); } targetDescriptor = this.Context.GetEntityDescriptor(target); } // if the entity is already tracked, then just set/attach the link. However, do // not try to attach the link if the target is in Deleted state. if (!this.IsContextTrackingLink(source, sourceProperty, target)) { if (this.AttachBehavior) { if (targetDescriptor.State != EntityStates.Deleted) { this.Context.AttachLink(source, sourceProperty, target); } } else { this.Context.SetLink(source, sourceProperty, target); } } } else { Debug.Assert(!this.AttachBehavior, "During attach operations we must never perform operations for null values."); // The target could be null in which case we just need to set the link to null. this.Context.SetLink(source, sourceProperty, null); } }
/// <summary>Handle Adds to a tracked DataServiceCollection. Perform operations on context to reflect the changes.</summary> /// <param name="source">The source object that reference the target object through a navigation property.</param> /// <param name="sourceProperty">The navigation property in the source object that reference the target object.</param> /// <param name="sourceEntitySet">The entity set of the source object.</param> /// <param name="collection">The collection containing the target object.</param> /// <param name="target">The target entity to attach.</param> /// <param name="targetEntitySet">The entity set name of the target object.</param> internal void HandleAddEntity( object source, string sourceProperty, string sourceEntitySet, ICollection collection, object target, string targetEntitySet) { if (this.Context.ApplyingChanges) { return; } Debug.Assert( (source == null && sourceProperty == null) || (source != null && !String.IsNullOrEmpty(sourceProperty)), "source and sourceProperty should either both be present or both be absent."); Debug.Assert(target != null, "target must be provided by the caller."); Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "target must be an entity type."); // Do not handle add for already detached and deleted entities. if (source != null && this.IsDetachedOrDeletedFromContext(source)) { return; } // Do we need an operation on context to handle the Add operation. EntityDescriptor targetDescriptor = this.Context.GetEntityDescriptor(target); // Following are the conditions where context operation is required: // 1. Not a call to Load or constructions i.e. we have Add behavior and not Attach behavior // 2. Target entity is not being tracked // 3. Target is being tracked but there is no link between the source and target entity and target is in non-deleted state bool contextOperationRequired = !this.AttachBehavior && (targetDescriptor == null || (source != null && !this.IsContextTrackingLink(source, sourceProperty, target) && targetDescriptor.State != EntityStates.Deleted)); if (contextOperationRequired) { // First give the user code a chance to handle Add operation. if (this.CollectionChanged != null) { EntityCollectionChangedParams args = new EntityCollectionChangedParams( this.Context, source, sourceProperty, sourceEntitySet, collection, target, targetEntitySet, NotifyCollectionChangedAction.Add); if (this.CollectionChanged(args)) { return; } } } // The user callback code could detach the source. if (source != null && this.IsDetachedOrDeletedFromContext(source)) { throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource); } // Default implementation. targetDescriptor = this.Context.GetEntityDescriptor(target); if (source != null) { if (this.AttachBehavior) { // If the target entity is not being currently tracked, we attach both the // entity and the link between source and target entity. if (targetDescriptor == null) { BindingUtils.ValidateEntitySetName(targetEntitySet, target); this.Context.AttachTo(targetEntitySet, target); this.Context.AttachLink(source, sourceProperty, target); } else if (targetDescriptor.State != EntityStates.Deleted && !this.IsContextTrackingLink(source, sourceProperty, target)) { // If the target is already being tracked, then we attach the link if it // does not already exist between the source and target entities and the // target entity is not already in Deleted state. this.Context.AttachLink(source, sourceProperty, target); } } else { // The target will be added and link from source to target will get established in the code // below. Note that if there is already target present then we just try to establish the link // however, if the link is also already established then we don't do anything. if (targetDescriptor == null) { // If the entity is not tracked, that means the entity needs to // be added to the context. We need to call AddRelatedObject, // which adds via the parent (for e.g. POST Customers(0)/Orders). this.Context.AddRelatedObject(source, sourceProperty, target); } else if (targetDescriptor.State != EntityStates.Deleted && !this.IsContextTrackingLink(source, sourceProperty, target)) { // If the entity is already tracked, then we just add the link. // However, we would not do it if the target entity is already // in a Deleted state. this.Context.AddLink(source, sourceProperty, target); } } } else if (targetDescriptor == null) { // The source is null when the DataServiceCollection is the root collection. BindingUtils.ValidateEntitySetName(targetEntitySet, target); if (this.AttachBehavior) { // Attach the target entity. this.Context.AttachTo(targetEntitySet, target); } else { // Add the target entity. this.Context.AddObject(targetEntitySet, target); } } }