コード例 #1
0
        private void OnAddToCollection(
            NotifyCollectionChangedEventArgs eventArgs,
            object source,
            String sourceProperty,
            String targetEntitySet,
            object collection)
        {
            Debug.Assert(collection != null, "Must have a valid collection to which entities are added.");

            if (eventArgs.NewItems != null)
            {
                foreach (object target in eventArgs.NewItems)
                {
                    if (target == null)
                    {
                        throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNull("Add"));
                    }

                    if (!BindingEntityInfo.IsEntityType(target.GetType()))
                    {
                        throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNotEntity("Add"));
                    }

                    this.bindingGraph.AddEntity(
                        source,
                        sourceProperty,
                        target,
                        targetEntitySet,
                        collection);
                }
            }
        }
コード例 #2
0
 private void HandleUpdateEntity(object entity, string propertyName, object propertyValue)
 {
     if (!this.Context.ApplyingChanges)
     {
         if (!BindingEntityInfo.IsEntityType(entity.GetType(), this.Context.MaxProtocolVersion))
         {
             this.bindingGraph.GetAncestorEntityForComplexProperty(ref entity, ref propertyName, ref propertyValue);
         }
         if (!this.IsDetachedOrDeletedFromContext(entity))
         {
             if (this.EntityChanged != null)
             {
                 EntityChangedParams arg = new EntityChangedParams(this.Context, entity, propertyName, propertyValue, null, null);
                 if (this.EntityChanged(arg))
                 {
                     return;
                 }
             }
             if (this.IsContextTrackingEntity(entity))
             {
                 this.Context.UpdateObject(entity);
             }
         }
     }
 }
コード例 #3
0
ファイル: BindingGraph.cs プロジェクト: modulexcite/pash-1
 public void RemoveNonTrackedEntities()
 {
     foreach (object obj2 in this.graph.Select(o => BindingEntityInfo.IsEntityType(o.GetType(), this.observer.Context.MaxProtocolVersion) && !this.observer.IsContextTrackingEntity(o)))
     {
         this.graph.ClearEdgesForVertex(this.graph.LookupVertex(obj2));
     }
     this.RemoveUnreachableVertices();
 }
コード例 #4
0
        private bool IsDetachedOrDeletedFromContext(object entity)
        {
            Debug.Assert(entity != null, "entity must be provided.");
            Debug.Assert(BindingEntityInfo.IsEntityType(entity.GetType()), "entity must be an entity with keys.");

            EntityDescriptor descriptor = this.Context.GetEntityDescriptor(entity);

            return(descriptor == null || descriptor.State == EntityStates.Deleted);
        }
コード例 #5
0
ファイル: BindingGraph.cs プロジェクト: nuxleus/ODataLib
        public void RemoveNonTrackedEntities()
        {
            foreach (var entity in this.graph.Select(o => BindingEntityInfo.IsEntityType(o.GetType()) && !this.observer.IsContextTrackingEntity(o)))
            {
                this.graph.ClearEdgesForVertex(this.graph.LookupVertex(entity));
            }

            this.RemoveUnreachableVertices();
        }
コード例 #6
0
 private void ValidateDataServiceCollectionItem(object target)
 {
     if (target == null)
     {
         throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNull("Remove"));
     }
     if (!BindingEntityInfo.IsEntityType(target.GetType(), this.Context.MaxProtocolVersion))
     {
         throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNotEntity("Remove"));
     }
 }
コード例 #7
0
        private bool IsContextTrackingLink(object source, string sourceProperty, object target)
        {
            Debug.Assert(source != null, "source entity must be provided.");
            Debug.Assert(BindingEntityInfo.IsEntityType(source.GetType()), "source must be an entity with keys.");

            Debug.Assert(!String.IsNullOrEmpty(sourceProperty), "sourceProperty must be provided.");

            Debug.Assert(target != null, "target entity must be provided.");
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "target must be an entity with keys.");

            return(this.Context.GetLinkDescriptor(source, sourceProperty, target) != default(LinkDescriptor));
        }
コード例 #8
0
        private void ValidateCollectionItem(object target)
        {
            if (target == null)
            {
                throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNull("Remove"));
            }

            if (!BindingEntityInfo.IsEntityType(target.GetType()))
            {
                throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNotEntity("Remove"));
            }
        }
コード例 #9
0
        /// <summary>
        /// Handle changes to an entity object tracked by the BindingObserver
        /// </summary>
        /// <param name="entity">The entity object that has changed.</param>
        /// <param name="propertyName">The property of the target entity object that has changed.</param>
        /// <param name="propertyValue">The value of the changed property of the target object.</param>
        private void HandleUpdateEntity(object entity, string propertyName, object propertyValue)
        {
            Debug.Assert(!this.AttachBehavior || this.Context.ApplyingChanges, "Entity updates must not happen during Attach or construction phases, deserialization case is the exception.");

            if (this.Context.ApplyingChanges)
            {
                return;
            }

            // For complex types, we will perform notification and update on the closest ancestor entity using the farthest ancestor complex property.
            if (!BindingEntityInfo.IsEntityType(entity.GetType()))
            {
                this.bindingGraph.GetAncestorEntityForComplexProperty(ref entity, ref propertyName, ref propertyValue);
            }

            Debug.Assert(entity != null, "entity must be provided for update operations.");
            Debug.Assert(BindingEntityInfo.IsEntityType(entity.GetType()), "entity must be an entity with keys.");
            Debug.Assert(!String.IsNullOrEmpty(propertyName) || propertyValue == null, "When propertyName is null no propertyValue should be provided.");

            // Do not handle update for detached and deleted entities.
            if (this.IsDetachedOrDeletedFromContext(entity))
            {
                return;
            }

            // First give the user code a chance to handle Update operation.
            if (this.EntityChanged != null)
            {
                EntityChangedParams args = new EntityChangedParams(
                    this.Context,
                    entity,
                    propertyName,
                    propertyValue,
                    null,
                    null);

                if (this.EntityChanged(args))
                {
                    return;
                }
            }

            // Default implementation.
            // The user callback code could detach the entity.
            if (this.IsContextTrackingEntity(entity))
            {
                // Let UpdateObject check the state of the entity.
                this.Context.UpdateObject(entity);
            }
        }
コード例 #10
0
ファイル: BindingEntityInfo.cs プロジェクト: nuxleus/ODataLib
        internal static string GetEntitySet(
            object target,
            string targetEntitySet)
        {
            Debug.Assert(target != null, "Argument 'target' cannot be null.");
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type.");

            if (!String.IsNullOrEmpty(targetEntitySet))
            {
                return(targetEntitySet);
            }
            else
            {
                return(BindingEntityInfo.GetEntitySetAttribute(target.GetType()));
            }
        }
コード例 #11
0
 private void OnAddToDataServiceCollection(NotifyCollectionChangedEventArgs eventArgs, object source, string sourceProperty, string targetEntitySet, object collection)
 {
     if (eventArgs.NewItems != null)
     {
         foreach (object obj2 in eventArgs.NewItems)
         {
             if (obj2 == null)
             {
                 throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNull("Add"));
             }
             if (!BindingEntityInfo.IsEntityType(obj2.GetType(), this.Context.MaxProtocolVersion))
             {
                 throw new InvalidOperationException(Strings.DataBinding_BindingOperation_ArrayItemNotEntity("Add"));
             }
             this.bindingGraph.AddEntity(source, sourceProperty, obj2, targetEntitySet, collection);
         }
     }
 }
コード例 #12
0
        private void HandleUpdateEntity(object entity, string propertyName, object propertyValue)
        {
            Debug.Assert(!this.AttachBehavior || this.Context.ApplyingChanges, "Entity updates must not happen during Attach or construction phases, deserialization case is the exception.");

            if (this.Context.ApplyingChanges)
            {
                return;
            }

            if (!BindingEntityInfo.IsEntityType(entity.GetType()))
            {
                this.bindingGraph.GetAncestorEntityForComplexProperty(ref entity, ref propertyName, ref propertyValue);
            }

            Debug.Assert(entity != null, "entity must be provided for update operations.");
            Debug.Assert(BindingEntityInfo.IsEntityType(entity.GetType()), "entity must be an entity with keys.");
            Debug.Assert(!String.IsNullOrEmpty(propertyName) || propertyValue == null, "When propertyName is null no propertyValue should be provided.");

            if (this.IsDetachedOrDeletedFromContext(entity))
            {
                return;
            }

            if (this.EntityChanged != null)
            {
                EntityChangedParams args = new EntityChangedParams(
                    this.Context,
                    entity,
                    propertyName,
                    propertyValue,
                    null,
                    null);

                if (this.EntityChanged(args))
                {
                    return;
                }
            }

            if (this.IsContextTrackingEntity(entity))
            {
                this.Context.UpdateObject(entity);
            }
        }
コード例 #13
0
        internal void StartTracking <T>(DataServiceCollection <T> collection, string collectionEntitySet)
        {
            Debug.Assert(collection != null, "Only constructed collections are tracked.");

            if (!BindingEntityInfo.IsEntityType(typeof(T)))
            {
                throw new ArgumentException(Strings.DataBinding_DataServiceCollectionArgumentMustHaveEntityType(typeof(T)));
            }

            try
            {
                this.AttachBehavior = true;

                this.bindingGraph.AddCollection(null, null, collection, collectionEntitySet);
            }
            finally
            {
                this.AttachBehavior = false;
            }
        }
コード例 #14
0
 private void StartTracking(DataServiceContext context, IEnumerable <T> items, string entitySet, Func <EntityChangedParams, bool> entityChanged, Func <EntityCollectionChangedParams, bool> collectionChanged)
 {
     if (!BindingEntityInfo.IsEntityType(typeof(T), context.MaxProtocolVersion))
     {
         throw new ArgumentException(Strings.DataBinding_DataServiceCollectionArgumentMustHaveEntityType(typeof(T)));
     }
     this.observer = new BindingObserver(context, entityChanged, collectionChanged);
     if (items != null)
     {
         try
         {
             this.InternalLoadCollection(items);
         }
         catch
         {
             this.observer = null;
             throw;
         }
     }
     this.observer.StartTracking <T>((DataServiceCollection <T>) this, entitySet);
     this.rootCollection = true;
 }
コード例 #15
0
        /// <summary>Start tracking the specified DataServiceCollection.</summary>
        /// <typeparam name="T">An entity type.</typeparam>
        /// <param name="collection">An DataServiceCollection.</param>
        /// <param name="collectionEntitySet">The entity set of the elements in <paramref name="collection"/>.</param>
        internal void StartTracking <T>(DataServiceCollection <T> collection, string collectionEntitySet)
        {
            Debug.Assert(collection != null, "Only constructed collections are tracked.");

            // Verify that T corresponds to an entity type.
            if (!BindingEntityInfo.IsEntityType(typeof(T)))
            {
                throw new ArgumentException(Strings.DataBinding_DataServiceCollectionArgumentMustHaveEntityType(typeof(T)));
            }

            try
            {
                this.AttachBehavior = true;

                // Recursively traverse the entire object graph under the root collection.
                this.bindingGraph.AddCollection(null, null, collection, collectionEntitySet);
            }
            finally
            {
                this.AttachBehavior = false;
            }
        }
コード例 #16
0
        /// <summary>
        /// Get the entity set name for the target entity object.
        /// </summary>
        /// <param name="target">An entity object.</param>
        /// <param name="targetEntitySet">The 'currently known' entity set name for the target object.</param>
        /// <returns>The entity set name for the target object.</returns>
        /// <remarks>
        /// Allow user code to provide the entity set name. If user code does not provide the entity set name, then
        /// this method will get the entity set name from the value of the EntitySetAttribute.
        /// The 'currently known' entity set name for top level collections can be provided through OEC constructor
        /// </remarks>
        internal static string GetEntitySet(
            object target,
            string targetEntitySet)
        {
            Debug.Assert(target != null, "Argument 'target' cannot be null.");
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type.");

            // Here's the rules in order of priority for resolving entity set name
            // 1. EntitySet name passed in the constructor or extension methods of DataServiceCollection
            // 2. EntitySet name specified in the EntitySet attribute by the code gen. {Remember this attribute is
            //    not generated in case of MEST)
            if (!String.IsNullOrEmpty(targetEntitySet))
            {
                return(targetEntitySet);
            }
            else
            {
                // If there is not a 'currently known' entity set name to validate against, then there must be
                // EntitySet attribute on the entity type
                return(BindingEntityInfo.GetEntitySetAttribute(target.GetType()));
            }
        }
コード例 #17
0
        /// <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);
                }
            }
        }
コード例 #18
0
ファイル: BindingEntityInfo.cs プロジェクト: nuxleus/ODataLib
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);

            bindingEntityInfo.EntitySet  = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
            bindingEntityInfo.ClientType = ClientType.Create(entityType);

            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
            {
                BindingPropertyInfo bpi = null;

                Type propertyType = p.PropertyType;

                if (p.CollectionType != null)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindCollection
                        };
                    }
                }
                else
                if (BindingEntityInfo.IsEntityType(propertyType))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else
                if (BindingEntityInfo.CanBeComplexProperty(p))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
コード例 #19
0
        /// <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);
            }
        }
コード例 #20
0
        /// <summary>Handle Deletes from 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.</param>
        /// <param name="targetEntitySet">The entity set name of the target object.</param>
        internal void HandleDeleteEntity(
            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.");

            Debug.Assert(!this.AttachBehavior, "AttachBehavior is only allowed during Construction and Load when this method should never be entered.");

            // Do not handle delete for already detached and deleted entities.
            if (source != null && this.IsDetachedOrDeletedFromContext(source))
            {
                return;
            }

            // Do we need an operation on context to handle the Delete operation.
            // Detach behavior is special because it is only applicable in Clear
            // cases, where we don't callback users for detach nofications.
            bool contextOperationRequired = this.IsContextTrackingEntity(target) && !this.DetachBehavior;

            if (contextOperationRequired)
            {
                // First give the user code a chance to handle Delete operation.
                if (this.CollectionChanged != null)
                {
                    EntityCollectionChangedParams args = new EntityCollectionChangedParams(
                        this.Context,
                        source,
                        sourceProperty,
                        sourceEntitySet,
                        collection,
                        target,
                        targetEntitySet,
                        NotifyCollectionChangedAction.Remove);

                    if (this.CollectionChanged(args))
                    {
                        return;
                    }
                }
            }

            // The user callback code could detach the source.
            if (source != null && !this.IsContextTrackingEntity(source))
            {
                throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource);
            }

            // Default implementation.
            // Remove the entity from the context if it is currently being tracked.
            if (this.IsContextTrackingEntity(target))
            {
                if (this.DetachBehavior)
                {
                    this.Context.Detach(target);
                }
                else
                {
                    this.Context.DeleteObject(target);
                }
            }
        }
コード例 #21
0
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet  = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
            bindingEntityInfo.ClientType = ClientType.Create(entityType);

            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
            {
                BindingPropertyInfo bpi = null;

                Type propertyType = p.PropertyType;

                if (p.CollectionType != null)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindCollection
                        };
                    }
                }
                else
                if (BindingEntityInfo.IsEntityType(propertyType))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else
                if (BindingEntityInfo.CanBeComplexProperty(p))
                {
                    // Add complex types and nothing else.
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For complex types only treat complex typed properties as observable, we are not going to observer entity typed or primitive properties.
                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
コード例 #22
0
ファイル: BindingEntityInfo.cs プロジェクト: tapika/swupd
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <param name="model">The client model.</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType, ClientEdmModel model)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            // EntitySetAttribute does not allow multiples, so there can be at most 1 instance on the type.
            EntitySetAttribute entitySetAttribute = (EntitySetAttribute)entityType.GetCustomAttributes(typeof(EntitySetAttribute), true).SingleOrDefault();

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet  = entitySetAttribute != null ? entitySetAttribute.EntitySet : null;
            bindingEntityInfo.ClientType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityType));

            foreach (ClientPropertyAnnotation p in bindingEntityInfo.ClientType.Properties())
            {
                BindingPropertyInfo bpi = null;
                Type propertyType       = p.PropertyType;

                if (p.IsStreamLinkProperty)
                {
                    // DataServiceStreamLink is not mutable externally
                    // It implements INPC to notify controls about our updates
                    // We should ignore its events since we are the only one updating it.
                    continue;
                }
                else if (p.IsPrimitiveOrComplexCollection)
                {
                    Debug.Assert(!BindingEntityInfo.IsDataServiceCollection(propertyType, model), "DataServiceCollection cannot be the type that backs collections of primitives or complex types.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection
                    };
                }
                else if (p.IsEntityCollection)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType, model))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindDataServiceCollection
                        };
                    }
                }
                else if (BindingEntityInfo.IsEntityType(propertyType, model))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else if (BindingEntityInfo.CanBeComplexType(propertyType))
                {
                    // Add complex types and nothing else.
                    Debug.Assert(!p.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For entity types, all of the above types of properties are interesting.
                    // For complex types, only observe collections and complex type properties.
                    if (bindingEntityInfo.ClientType.IsEntityType ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
コード例 #23
0
        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);
            }
        }
コード例 #24
0
        internal void HandleDeleteEntity(
            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.");

            Debug.Assert(!this.AttachBehavior, "AttachBehavior is only allowed during Construction and Load when this method should never be entered.");

            if (source != null && this.IsDetachedOrDeletedFromContext(source))
            {
                return;
            }

            bool contextOperationRequired = this.IsContextTrackingEntity(target) && !this.DetachBehavior;

            if (contextOperationRequired)
            {
                if (this.CollectionChanged != null)
                {
                    EntityCollectionChangedParams args = new EntityCollectionChangedParams(
                        this.Context,
                        source,
                        sourceProperty,
                        sourceEntitySet,
                        collection,
                        target,
                        targetEntitySet,
                        NotifyCollectionChangedAction.Remove);

                    if (this.CollectionChanged(args))
                    {
                        return;
                    }
                }
            }

            if (source != null && !this.IsContextTrackingEntity(source))
            {
                throw new InvalidOperationException(Strings.DataBinding_BindingOperation_DetachedSource);
            }

            if (this.IsContextTrackingEntity(target))
            {
                if (this.DetachBehavior)
                {
                    this.Context.Detach(target);
                }
                else
                {
                    this.Context.DeleteObject(target);
                }
            }
        }
コード例 #25
0
        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);
                }
            }
        }