/// <summary>
        /// Populate this collection with another collection of items
        /// </summary>
        /// <param name="items">The items to populate this collection with</param>
        private void InternalLoadCollection(IEnumerable <T> items)
        {
            Debug.Assert(items != null, "items != null");
            // For SDP, we must execute the Query implicitly
            DataServiceQuery <T> query = items as DataServiceQuery <T>;

            if (query != null)
            {
                items = query.Execute() as QueryOperationResponse <T>;
            }

            foreach (T item in items)
            {
                // if this is too slow, consider hashing the set
                // or just use LoadProperties
                if (!this.Contains(item))
                {
                    this.Add(item);
                }
            }

            QueryOperationResponse <T> response = items as QueryOperationResponse <T>;

            if (response != null)
            {
                // this should never be throwing (since we've enumerated already)!
                // Note: Inner collection's nextPartLinkUri is set by the materializer
                this.continuation = response.GetContinuation();
            }
            else
            {
                this.continuation = null;
            }
        }
示例#2
0
        /// <summary>Set the continuation for the following results for a collection.</summary>
        /// <param name="collection">The collection to set the links to</param>
        /// <param name="continuation">The continuation for the collection.</param>
        internal static void SetNextLinkForCollection(object collection, DataServiceQueryContinuation continuation)
        {
            Debug.Assert(collection != null, "collection != null");

            // We do a convention call for setting Continuation. We'll invoke this
            // for all properties named 'Continuation' that is a DataServiceQueryContinuation
            // (assigning to a single one would make it inconsistent if reflection
            // order is changed).
            foreach (var property in collection.GetType().GetPublicProperties(true /*instanceOnly*/))
            {
                if (property.Name != "Continuation" || !property.CanWrite)
                {
                    continue;
                }

                if (typeof(DataServiceQueryContinuation).IsAssignableFrom(property.PropertyType))
                {
                    property.SetValue(collection, continuation, null);
                }
            }
        }
示例#3
0
        /// <summary>
        /// Returns the next link URI for the collection key
        /// </summary>
        /// <param name="key">The collection for which the Uri is returned, or null, if the top level link is to be returned</param>
        /// <returns>An Uri pointing to the next page for the collection</returns>
        internal virtual DataServiceQueryContinuation GetContinuation(IEnumerable key)
        {
            Debug.Assert(this.materializer != null, "Materializer is null!");

            DataServiceQueryContinuation result;

            if (key == null)
            {
                if ((this.expectingPrimitiveValue && !this.moved) || (!this.expectingPrimitiveValue && !this.materializer.IsEndOfStream))
                {
                    // expectingSingleValue && !moved : haven't started parsing single value (single value should not have next link anyway)
                    // !expectingSingleValue && !IsEndOfStream : collection type feed did not finish parsing yet
                    throw new InvalidOperationException(Strings.MaterializeFromAtom_TopLevelLinkNotAvailable);
                }

                // we have already moved to the end of stream
                // are we singleton or just an entry?
                if (this.expectingPrimitiveValue || this.materializer.CurrentFeed == null)
                {
                    result = null;
                }
                else
                {
                    // DEVNOTE(pqian): The next link uri should never be edited by the client, and therefore it must be absolute
                    result = DataServiceQueryContinuation.Create(
                        this.materializer.CurrentFeed.NextPageLink,
                        this.materializer.MaterializeEntryPlan);
                }
            }
            else
            {
                if (!this.materializer.NextLinkTable.TryGetValue(key, out result))
                {
                    // someone has asked for a collection that's "out of scope" or doesn't exist
                    throw new ArgumentException(Strings.MaterializeFromAtom_CollectionKeyNotPresentInLinkTable);
                }
            }

            return(result);
        }
示例#4
0
        /// <summary>
        /// Populate this collection with another collection of items
        /// </summary>
        /// <param name="items">The items to populate this collection with</param>
        private void InternalLoadCollection(IEnumerable <T> items)
        {
            Debug.Assert(items != null, "items != null");
#if !ASTORIA_LIGHT && !PORTABLELIB
            // For SDP, we must execute the Query implicitly
            DataServiceQuery <T> query = items as DataServiceQuery <T>;
            if (query != null)
            {
                items = query.Execute() as QueryOperationResponse <T>;
            }
#else
            Debug.Assert(!(items is DataServiceQuery), "SL Client using DSQ as items...should have been caught by ValidateIteratorParameter.");
#endif

            foreach (T item in items)
            {
                // if this is too slow, consider hashing the set
                // or just use LoadProperties
                if (!this.Contains(item))
                {
                    this.Add(item);
                }
            }

            QueryOperationResponse <T> response = items as QueryOperationResponse <T>;
            if (response != null)
            {
                // this should never be throwing (since we've enumerated already)!
                // Note: Inner collection's nextPartLinkUri is set by the materializer
                this.continuation = response.GetContinuation();
            }
            else
            {
                this.continuation = null;
            }
        }
示例#5
0
        private MaterializeAtom ReadPropertyFromAtom(ClientPropertyAnnotation property)
        {
            DataServiceContext context = (DataServiceContext)this.Source;
            bool merging = context.ApplyingChanges;

            try
            {
                context.ApplyingChanges = true;

                // store the results so that they can be there in the response body.
                Type  elementType = property.IsEntityCollection ? property.EntityCollectionItemType : property.NullablePropertyType;
                IList results     = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(elementType));

                DataServiceQueryContinuation continuation = null;

                // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                using (MaterializeAtom materializer = this.GetMaterializer(this.plan))
                {
                    Debug.Assert(materializer != null, "materializer != null -- otherwise GetMaterializer() returned null rather than empty");

#if ASTORIA_OPEN_OBJECT
                    object openProperties = null;
#endif
                    // when SetLink to null, we cannot get materializer because have no-content response.
                    if (materializer.IsNoContentResponse() &&
                        property.GetValue(entity) != null &&
                        context.MergeOption != MergeOption.AppendOnly &&
                        context.MergeOption != MergeOption.NoTracking)
                    {
                        property.SetValue(this.entity, null, propertyName, false);
                    }
                    else
                    {
                        foreach (object child in materializer)
                        {
                            if (property.IsEntityCollection)
                            {
                                results.Add(child);
                            }
                            else if (property.IsPrimitiveOrEnumOrComplexCollection)
                            {
                                Debug.Assert(property.PropertyType.IsAssignableFrom(child.GetType()), "Created instance for storing collection items has to be compatible with the actual one.");

                                // Collection materialization rules requires to clear the collection if not null or set the property first and then add the collection items
                                object collectionInstance = property.GetValue(this.entity);
                                if (collectionInstance == null)
                                {
                                    // type of child has been resolved as per rules for collections so it is the correct type to instantiate
                                    collectionInstance = Activator.CreateInstance(child.GetType());

                                    // allowAdd is false - we need to assign instance as the new property value
                                    property.SetValue(this.entity, collectionInstance, this.propertyName, false /* allowAdd? */);
                                }
                                else
                                {
                                    // Clear existing collection
                                    property.ClearBackingICollectionInstance(collectionInstance);
                                }

                                foreach (var collectionItem in (IEnumerable)child)
                                {
                                    Debug.Assert(property.PrimitiveOrComplexCollectionItemType.IsAssignableFrom(collectionItem.GetType()), "Type of materialized collection items have to be compatible with the type of collection items in the actual collection property.");
                                    property.AddValueToBackingICollectionInstance(collectionInstance, collectionItem);
                                }

                                results.Add(collectionInstance);
                            }
                            else
                            {
#if ASTORIA_OPEN_OBJECT
                                property.SetValue(this.entity, child, this.propertyName, ref openProperties, false);
#else
                                // it is either primitive type, complex type or 1..1 navigation property so we just allow setting the value but not adding.
                                property.SetValue(this.entity, child, this.propertyName, false);
                                results.Add(child);
#endif
                            }
                        }
                    }

                    continuation = materializer.GetContinuation(null);
                }

                return(MaterializeAtom.CreateWrapper(context, results, continuation));
            }
            finally
            {
                context.ApplyingChanges = merging;
            }
        }
示例#6
0
 /// <summary>
 /// Creates a wrapper for raw results
 /// </summary>
 /// <param name="context">Context of expression to analyze.</param>
 /// <param name="results">the results to wrap</param>
 /// <param name="continuation">The continuation for this query.</param>
 internal ResultsWrapper(DataServiceContext context, IEnumerable results, DataServiceQueryContinuation continuation)
 {
     this.context      = context;
     this.results      = results ?? Enumerable.Empty <object>();
     this.continuation = continuation;
 }
示例#7
0
 /// <summary>Creates a materializer for partial result sets.</summary>
 /// <param name="context">Context of expression to analyze.</param>
 /// <param name="results">The current page of results</param>
 /// <param name="continuation">The continuation for the results.</param>
 /// <returns>A new materializer.</returns>
 internal static MaterializeAtom CreateWrapper(DataServiceContext context, IEnumerable results, DataServiceQueryContinuation continuation)
 {
     return(new ResultsWrapper(context, results, continuation));
 }