Example #1
0
        /// <summary>
        /// Applies the values of a nested <paramref name="feed"/> to the collection
        /// <paramref name="property"/> of the specified <paramref name="entry"/>.
        /// </summary>
        /// <param name="entry">Entry with collection to be modified.</param>
        /// <param name="property">Collection property on the entry.</param>
        /// <param name="feed">Values to apply onto the collection.</param>
        /// <param name="includeLinks">Whether links that are expanded should be materialized.</param>
        private void ApplyFeedToCollection(
            MaterializerEntry entry,
            ClientPropertyAnnotation property,
            ODataResourceSet feed,
            bool includeLinks)
        {
            Debug.Assert(entry.Entry != null, "entry != null");
            Debug.Assert(property != null, "property != null");
            Debug.Assert(feed != null, "feed != null");

            ClientEdmModel       edmModel       = this.MaterializerContext.Model;
            ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType));

            IEnumerable <ODataResource> entries = MaterializerFeed.GetFeed(feed).Entries;

            foreach (ODataResource feedEntry in entries)
            {
                this.Materialize(MaterializerEntry.GetEntry(feedEntry), collectionType.ElementType, includeLinks);
            }

            ProjectionPlan continuationPlan = includeLinks ?
                                              ODataEntityMaterializer.CreatePlanForDirectMaterialization(property.ResourceSetItemType) :
                                              ODataEntityMaterializer.CreatePlanForShallowMaterialization(property.ResourceSetItemType);

            this.ApplyItemsToCollection(
                entry,
                property,
                entries.Select(e => MaterializerEntry.GetEntry(e).ResolvedObject),
                feed.NextPageLink,
                continuationPlan,
                false);
        }
        /// <summary>
        /// Read a feed or entry, with the expected type.
        /// </summary>
        /// <returns>true if a value was read, otherwise false</returns>
        public bool Read()
        {
            if (this.feedEntries != null)
            {
                // ISSUE: this might throw - refactor?
                if (this.feedEntries.MoveNext())
                {
                    this.currentEntry = this.feedEntries.Current;
                    return(true);
                }
                else
                {
                    this.feedEntries  = null;
                    this.currentEntry = null;
                }
            }

            switch (this.reader.State)
            {
            case ODataReaderState.Completed:
                this.currentEntry = null;
                return(false);

            case ODataReaderState.Start:
            {
                ODataFeed         feed;
                MaterializerEntry entryAndState;
                if (this.TryReadFeedOrEntry(true, out feed, out entryAndState))
                {
                    this.currentEntry = entryAndState != null ? entryAndState.Entry : null;
                    this.currentFeed  = feed;
                    if (this.currentFeed != null)
                    {
                        this.feedEntries = MaterializerFeed.GetFeed(this.currentFeed).Entries.GetEnumerator();
                    }

                    return(true);
                }
                else
                {
                    throw new NotImplementedException();
                }
            }

            case ODataReaderState.FeedEnd:
            case ODataReaderState.EntryEnd:
                if (this.TryRead() || this.reader.State != ODataReaderState.Completed)
                {
                    throw DSClient.Error.InternalError(InternalError.UnexpectedReadState);
                }

                this.currentEntry = null;
                return(false);

            default:
                throw DSClient.Error.InternalError(InternalError.UnexpectedReadState);
            }
        }
        /// <summary>
        /// The count tag's value, if requested
        /// </summary>
        /// <param name="readIfNoFeed">Should read pull if no feed exists.</param>
        /// <returns>The count value returned from the server</returns>
        public long GetCountValue(bool readIfNoFeed)
        {
            if (this.currentFeed == null && this.currentEntry == null && readIfNoFeed && this.TryReadFeed(true, out this.currentFeed))
            {
                this.feedEntries = MaterializerFeed.GetFeed(this.currentFeed).Entries.GetEnumerator();
            }

            if (this.currentFeed != null && this.currentFeed.Count.HasValue)
            {
                return(this.currentFeed.Count.Value);
            }

            throw new InvalidOperationException(DSClient.Strings.MaterializeFromAtom_CountNotPresent);
        }
        /// <summary>
        /// Reads the remainder of a feed.
        /// </summary>
        /// <param name="lazy">if set to <c>true</c> [lazy].</param>
        /// <returns>A feed.</returns>
        private ODataResourceSet ReadFeedCore(bool lazy)
        {
            this.ExpectState(ODataReaderState.ResourceSetStart);

            ODataResourceSet result = (ODataResourceSet)this.reader.Item;

            IEnumerable <ODataResource> lazyEntries = this.LazyReadEntries();

            if (lazy)
            {
                MaterializerFeed.CreateFeed(result, lazyEntries);
            }
            else
            {
                MaterializerFeed.CreateFeed(result, new List <ODataResource>(lazyEntries));
            }

            return(result);
        }
Example #5
0
        /// <summary>Materializes the specified <paramref name="entry"/> as dynamic property.</summary>
        /// <param name="entry">Entry with object to materialize.</param>
        /// <param name="link">Nested resource link as parsed.</param>
        private void MaterializeDynamicProperty(MaterializerEntry entry, ODataNestedResourceInfo link)
        {
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise not resolved/created!");
            Debug.Assert(link != null, "link != null");

            ClientEdmModel model = this.MaterializerContext.Model;

            IDictionary <string, object> containerProperty;

            // Stop if owning type is not an open type
            // Or container property is not found
            // Or key with matching name already exists in the dictionary
            if (!ClientTypeUtil.IsInstanceOfOpenType(entry.ResolvedObject, model) ||
                !ClientTypeUtil.TryGetContainerProperty(entry.ResolvedObject, out containerProperty) ||
                containerProperty.ContainsKey(link.Name))
            {
                return;
            }

            MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link);

            if (linkState == null || (linkState.Entry == null && linkState.Feed == null))
            {
                return;
            }

            // NOTE: ODL (and OData WebApi) support navigational property on complex types
            // That support has not yet been implemented in OData client

            // An entity or entity collection as a dynamic property currently doesn't work as expected
            // due to the absence of a navigational property definition in the metadata
            // to express the relationship between that entity and the parent entity - unless they're the same type!
            // Only materialize a nested resource if its a complex or complex collection

            if (linkState.Feed != null)
            {
                string collectionTypeName     = linkState.Feed.TypeName; // TypeName represents a collection e.g. Collection(NS.Type)
                string collectionItemTypeName = CommonUtil.GetCollectionItemTypeName(collectionTypeName, false);
                // Highly unlikely, but the method return null if the typeName argument does not meet certain expectations
                if (collectionItemTypeName == null)
                {
                    return;
                }

                Type collectionItemType = ResolveClientTypeForDynamicProperty(collectionItemTypeName, entry.ResolvedObject);

                if (collectionItemType != null && ClientTypeUtil.TypeIsComplex(collectionItemType, model))
                {
                    Type  collectionType = typeof(System.Collections.ObjectModel.Collection <>).MakeGenericType(new Type[] { collectionItemType });
                    IList collection     = (IList)Util.ActivatorCreateInstance(collectionType);

                    IEnumerable <ODataResource> feedEntries = MaterializerFeed.GetFeed(linkState.Feed).Entries;
                    foreach (ODataResource feedEntry in feedEntries)
                    {
                        MaterializerEntry linkEntry = MaterializerEntry.GetEntry(feedEntry);
                        this.Materialize(linkEntry, collectionItemType, false /*includeLinks*/);
                        collection.Add(linkEntry.ResolvedObject);
                    }
                    containerProperty.Add(link.Name, collection);
                }
            }
            else
            {
                MaterializerEntry linkEntry = linkState.Entry;
                Type itemType = ResolveClientTypeForDynamicProperty(linkEntry.Entry.TypeName, entry.ResolvedObject);

                if (itemType != null && ClientTypeUtil.TypeIsComplex(itemType, model))
                {
                    this.Materialize(linkEntry, itemType, false /*includeLinks*/);
                    containerProperty.Add(link.Name, linkEntry.ResolvedObject);
                }
            }
        }