Example #1
0
        /// <summary>Attempts to resolve an entry from those tracked in the log.</summary>
        /// <param name="entry">Entry to resolve.</param>
        /// <param name="existingEntry">
        /// After invocation, an existing entry with the same identity as
        /// <paramref name="entry"/>; possibly null.
        /// </param>
        /// <returns>true if an existing entry was found; false otherwise.</returns>
        internal bool TryResolve(MaterializerEntry entry, out MaterializerEntry existingEntry)
        {
            Debug.Assert(entry.Entry != null, "entry != null");
            Debug.Assert(entry.Id != null, "entry.Id != null");
            Debug.Assert(entry.IsTracking, "Should not be trying to resolve the entry if entry.isTracking is false.");

            ODataResource existingODataEntry;

            if (this.identityStack.TryGetValue(entry.Id, out existingODataEntry))
            {
                existingEntry = MaterializerEntry.GetEntry(existingODataEntry);
                return(true);
            }

            if (this.appendOnlyEntries.TryGetValue(entry.Id, out existingODataEntry))
            {
                // The AppendOnly entries are valid only as long as they were not modified
                // between calls to .MoveNext().
                EntityStates state;
                this.entityTracker.TryGetEntity(entry.Id, out state);
                if (state == EntityStates.Unchanged)
                {
                    existingEntry = MaterializerEntry.GetEntry(existingODataEntry);
                    return(true);
                }
                else
                {
                    this.appendOnlyEntries.Remove(entry.Id);
                }
            }

            existingEntry = default(MaterializerEntry);
            return(false);
        }
 /// <summary>Projects a simple value from the specified <paramref name="path"/>.</summary>
 /// <param name="materializer">Materializer under which projection is taking place.</param>
 /// <param name="entry">Root entry for paths.</param>
 /// <param name="expectedType">Expected type for <paramref name="entry"/>.</param>
 /// <param name="path">Path to pull value for.</param>
 /// <returns>The value for the specified <paramref name="path"/>.</returns>
 /// <remarks>
 /// This method will not instantiate entity types, except to satisfy requests
 /// for payload-driven feeds or leaf entities.
 /// </remarks>
 internal static object ProjectionValueForPath(object materializer, object entry, Type expectedType, object path)
 {
     Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())");
     Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)");
     Debug.Assert(path.GetType() == typeof(ProjectionPath), "path.GetType() == typeof(ProjectionPath)");
     return(((ODataEntityMaterializer)materializer).ProjectionValueForPath(MaterializerEntry.GetEntry((ODataResource)entry), expectedType, (ProjectionPath)path));
 }
Example #3
0
        internal ODataEntriesEntityMaterializer CreateODataEntriesEntityMaterializer(
            List <ODataResource> resources,
            Type resourceType,
            TestMaterializerContext materializerContext = null)
        {
            var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
            var context        = new DataServiceContext();

            var resourceSet = new ODataResourceSet();

            MaterializerFeed.CreateFeed(resourceSet, resources);
            resources.ForEach(r =>
            {
                if (r == null)
                {
                    MaterializerEntry.CreateEmpty();
                }
                else
                {
                    MaterializerEntry.CreateEntry(r, ODataFormat.Json, true, clientEdmModel);
                }
            });
            materializerContext = materializerContext ?? new TestMaterializerContext()
            {
                Model = clientEdmModel, Context = context
            };
            var             adapter    = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
            QueryComponents components = new QueryComponents(new Uri("http://foo.com/Service"), new Version(4, 0), resourceType, null, new Dictionary <Expression, Expression>());

            return(new ODataEntriesEntityMaterializer(resources, materializerContext, adapter, components, resourceType, null, ODataFormat.Json));
        }
Example #4
0
        /// <summary>Tries to resolve the object as one from the context (only if tracking is enabled).</summary>
        /// <param name="entry">Entry to resolve.</param>
        /// <param name="expectedEntryType">Expected entry type for the specified <paramref name="entry"/>.</param>
        /// <returns>true if the entity was resolved; false otherwise.</returns>
        private bool TryResolveFromContext(MaterializerEntry entry, Type expectedEntryType)
        {
            Debug.Assert(entry.IsTracking, "Should not be trying to resolve the entry from the context if entry.isTracking is false.");

            // We should either create a new instance or grab one from the context.
            if (this.MergeOption != MergeOption.NoTracking)
            {
                EntityStates state;
                entry.ResolvedObject = this.EntityTracker.TryGetEntity(entry.Id, out state);
                if (entry.ResolvedObject != null)
                {
                    if (!expectedEntryType.IsInstanceOfType(entry.ResolvedObject))
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_Current(expectedEntryType, entry.ResolvedObject.GetType()));
                    }

                    ClientEdmModel edmModel = this.Model;
                    entry.ActualType            = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(entry.ResolvedObject.GetType()));
                    entry.EntityHasBeenResolved = true;

                    // Note that deleted items will have their properties overwritten even
                    // if PreserveChanges is used as a merge option.
                    entry.ShouldUpdateFromPayload =
                        this.MergeOption == MergeOption.OverwriteChanges ||
                        (this.MergeOption == MergeOption.PreserveChanges && state == EntityStates.Unchanged) ||
                        (this.MergeOption == MergeOption.PreserveChanges && state == EntityStates.Deleted);

                    this.MaterializationLog.FoundExistingInstance(entry);

                    return(true);
                }
            }

            return(false);
        }
Example #5
0
        public void MaterializeDerivedComplexForBaseComplexTypeProperty()
        {
            TestMaterializerContext context = new TestMaterializerContext();

            //In a true client, a TypeResolver will be used to resolve derived property type.
            context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
            {
                var edmType = context.Model.GetOrCreateEdmType(typeof(DerivedComplexType));
                return(new ClientTypeAnnotation(edmType, typeof(DerivedComplexType), "DerivedComplexType", context.Model));
            };

            var derivedResource = new ODataResource()
            {
                TypeName   = "DerivedComplexType",
                Properties = new ODataProperty[] { new ODataProperty {
                                                       Name = "DerivedProp", Value = 1
                                                   } }
            };

            var clientEdmModel    = new ClientEdmModel(ODataProtocolVersion.V4);
            var materializerEntry = MaterializerEntry.CreateEntry(derivedResource, ODataFormat.Json, true, clientEdmModel);

            this.CreateEntryMaterializationPolicy(context).Materialize(materializerEntry, typeof(ChildComplexType), false);

            var derived = materializerEntry.ResolvedObject as DerivedComplexType;

            Assert.NotNull(derived);
            Assert.Equal(1, derived.DerivedProp);
        }
Example #6
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);
        }
Example #7
0
 internal void AddedLink(MaterializerEntry source, string propertyName, object target)
 {
     if (this.Tracking && (ShouldTrackWithContext(source) && ShouldTrackWithContext(target, this.responseInfo.MaxProtocolVersion)))
     {
         LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added);
         this.links.Add(item);
     }
 }
Example #8
0
        /// <summary>
        /// Fires the end entry events.
        /// </summary>
        /// <param name="entry">The entry.</param>
        internal void FireEndEntryEvents(MaterializerEntry entry)
        {
            Debug.Assert(entry != null, "entry!=null");

            if (this.HasReadingEntityHandlers)
            {
                this.ExecuteEntityMaterializedActions(entry.Entry, entry.ResolvedObject);
            }
        }
Example #9
0
 internal void FoundTargetInstance(MaterializerEntry entry)
 {
     if (ShouldTrackWithContext(entry))
     {
         this.responseInfo.EntityTracker.AttachIdentity(entry.EntityDescriptor, this.mergeOption);
         this.identityStack.Add(entry.Id, entry.Entry);
         this.insertRefreshObject = entry.ResolvedObject;
     }
 }
 /// <summary>Checks whether the entity on the specified <paramref name="path"/> is null.</summary>
 /// <param name="entry">Root entry for paths.</param>
 /// <param name="expectedType">Expected type for <paramref name="entry"/>.</param>
 /// <param name="path">Path to pull value for.</param>
 /// <returns>Whether the specified <paramref name="path"/> is null.</returns>
 /// <remarks>
 /// This method will not instantiate entity types on the path.
 /// </remarks>
 internal static bool ProjectionCheckValueForPathIsNull(
     object entry,
     Type expectedType,
     object path)
 {
     Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)");
     Debug.Assert(path.GetType() == typeof(ProjectionPath), "path.GetType() == typeof(ProjectionPath)");
     return(ODataEntityMaterializer.ProjectionCheckValueForPathIsNull(MaterializerEntry.GetEntry((ODataResource)entry), expectedType, (ProjectionPath)path));
 }
Example #11
0
 internal void ApplyToContext()
 {
     if (this.Tracking)
     {
         foreach (KeyValuePair <string, ODataEntry> pair in this.identityStack)
         {
             MaterializerEntry entry    = MaterializerEntry.GetEntry(pair.Value);
             bool             mergeInfo = (entry.CreatedByMaterializer || (entry.ResolvedObject == this.insertRefreshObject)) || entry.ShouldUpdateFromPayload;
             EntityDescriptor trackedEntityDescriptor = this.responseInfo.EntityTracker.InternalAttachEntityDescriptor(entry.EntityDescriptor, false);
             MergeEntityDescriptorInfo(trackedEntityDescriptor, entry.EntityDescriptor, mergeInfo, this.mergeOption);
             if (mergeInfo && ((this.responseInfo.MergeOption != MergeOption.PreserveChanges) || (trackedEntityDescriptor.State != EntityStates.Deleted)))
             {
                 trackedEntityDescriptor.State = EntityStates.Unchanged;
             }
         }
         foreach (LinkDescriptor descriptor2 in this.links)
         {
             if (EntityStates.Added == descriptor2.State)
             {
                 if ((EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Target).State) || (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Source).State))
                 {
                     this.responseInfo.EntityTracker.DetachExistingLink(descriptor2, false);
                 }
                 else
                 {
                     this.responseInfo.EntityTracker.AttachLink(descriptor2.Source, descriptor2.SourceProperty, descriptor2.Target, this.mergeOption);
                 }
             }
             else
             {
                 if (EntityStates.Modified == descriptor2.State)
                 {
                     object target = descriptor2.Target;
                     if (MergeOption.PreserveChanges == this.mergeOption)
                     {
                         LinkDescriptor descriptor3 = this.responseInfo.EntityTracker.GetLinks(descriptor2.Source, descriptor2.SourceProperty).SingleOrDefault <LinkDescriptor>();
                         if ((descriptor3 != null) && (descriptor3.Target == null))
                         {
                             goto Label_0233;
                         }
                         if (((target != null) && (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(target).State)) || (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Source).State))
                         {
                             target = null;
                         }
                     }
                     this.responseInfo.EntityTracker.AttachLink(descriptor2.Source, descriptor2.SourceProperty, target, this.mergeOption);
                 }
                 else
                 {
                     this.responseInfo.EntityTracker.DetachExistingLink(descriptor2, false);
                 }
                 Label_0233 :;
             }
         }
     }
 }
Example #12
0
        /// <summary>
        /// Creates the materializer entry.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <param name="format">The format the entry was read in.</param>
        /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param>
        /// <param name="model">The client model.</param>
        /// <returns>A new materializer entry.</returns>
        public static MaterializerEntry CreateEntry(ODataResource entry, ODataFormat format, bool isTracking, ClientEdmModel model)
        {
            Debug.Assert(entry.GetAnnotation <MaterializerEntry>() == null, "MaterializerEntry has already been created.");

            MaterializerEntry materializerEntry = new MaterializerEntry(entry, format, isTracking, model);

            entry.SetAnnotation <MaterializerEntry>(materializerEntry);

            return(materializerEntry);
        }
Example #13
0
        /// <summary>
        /// Reads the remainder of an entry.
        /// </summary>
        /// <returns>An entry.</returns>
        private MaterializerEntry ReadEntryCore()
        {
            this.ExpectState(ODataReaderState.ResourceStart);

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

            MaterializerEntry entry;
            List <ODataNestedResourceInfo> navigationLinks = new List <ODataNestedResourceInfo>();

            if (result != null)
            {
                entry = MaterializerEntry.CreateEntry(
                    result,
                    this.readODataFormat,
                    this.mergeOption != MergeOption.NoTracking,
                    this.clientEdmModel);

                do
                {
                    this.AssertRead();

                    switch (this.reader.State)
                    {
                    case ODataReaderState.NestedResourceInfoStart:
                        // Cache the list of navigation links here but don't add them to the entry because all of the key properties may not be available yet.
                        navigationLinks.Add(this.ReadNestedResourceInfo());
                        break;

                    case ODataReaderState.ResourceEnd:
                        break;

                    default:
                        throw DSClient.Error.InternalError(InternalError.UnexpectedReadState);
                    }
                }while (this.reader.State != ODataReaderState.ResourceEnd);

                if (!entry.Entry.IsTransient)
                {
                    entry.UpdateEntityDescriptor();
                }
            }
            else
            {
                entry = MaterializerEntry.CreateEmpty();
                this.ReadAndExpectState(ODataReaderState.ResourceEnd);
            }

            // Add the navigation links here now that all of the property values have been read and are available to build the links.
            foreach (ODataNestedResourceInfo navigationLink in navigationLinks)
            {
                entry.AddNestedResourceInfo(navigationLink);
            }

            return(entry);
        }
Example #14
0
 internal void CreatedInstance(MaterializerEntry entry)
 {
     if (ShouldTrackWithContext(entry))
     {
         this.identityStack.Add(entry.Id, entry.Entry);
         if (this.mergeOption == MergeOption.AppendOnly)
         {
             this.appendOnlyEntries.Add(entry.Id, entry.Entry);
         }
     }
 }
        private MaterializerEntry CreateMaterializerEntry(ODataFormat format, Action <ODataEntry> modifyEntry = null)
        {
            var entry = new ODataEntry();

            if (modifyEntry != null)
            {
                modifyEntry(entry);
            }

            return(MaterializerEntry.CreateEntry(entry, format, true, this.clientModel));
        }
Example #16
0
        /// <summary>
        /// Invoke this method to notify the log that a link was removed
        /// from a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection from which <paramref name="target"/>
        /// was removed.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was removed.</param>
        internal void RemovedLink(MaterializerEntry source, string propertyName, object target)
        {
            Debug.Assert(source.Entry != null || source.ForLoadProperty, "source != null || source.ForLoadProperty");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (IsEntity(source) && IsEntity(target, this.clientEdmModel))
            {
                Debug.Assert(this.Tracking, "this.Tracking -- otherwise there's an 'if' missing (it happens to be that the assert holds for all current callers");
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Detached);
                this.links.Add(item);
            }
        }
Example #17
0
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="descriptor">descriptor whose response is getting processed.</param>
            /// <param name="headers">headers</param>
            /// <param name="statusCode">status code</param>
            /// <param name="responseVersion">Parsed response OData-Version header.</param>
            /// <param name="entry">atom entry, if there is a non-error response payload.</param>
            /// <param name="exception">exception, if the request threw an exception.</param>
            internal CachedResponse(Descriptor descriptor, HeaderCollection headers, HttpStatusCode statusCode, Version responseVersion, MaterializerEntry entry, Exception exception)
            {
                Debug.Assert(descriptor != null, "descriptor != null");
                Debug.Assert(headers != null, "headers != null");
                Debug.Assert(entry == null || (exception == null && descriptor.DescriptorKind == DescriptorKind.Entity), "if entry is specified, exception cannot be specified and entry must be a resource, since we expect responses only for entities");

                this.Descriptor        = descriptor;
                this.MaterializerEntry = entry;
                this.Exception         = exception;
                this.Headers           = headers;
                this.StatusCode        = statusCode;
                this.Version           = responseVersion;
            }
Example #18
0
        /// <summary>
        /// Invoke this method to notify the log that the
        /// target instance of a "directed" update was found.
        /// </summary>
        /// <param name="entry">Entry found.</param>
        /// <remarks>
        /// The target instance is typically the object that we
        /// expect will get refreshed by the response from a POST
        /// method.
        ///
        /// For example if a create a Customer and POST it to
        /// a service, the response of the POST will return the
        /// re-serialized instance, with (important!) server generated
        /// values and URIs.
        /// </remarks>
        internal void FoundTargetInstance(MaterializerEntry entry)
        {
            Debug.Assert(entry.Entry != null, "entry != null");
            Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise this is not a target");

            if (IsEntity(entry))
            {
                Debug.Assert(entry.IsTracking, "entry.isTracking == true, otherwise we should not be tracking this entry with the context.");

                this.entityTracker.AttachIdentity(entry.EntityDescriptor, this.mergeOption);
                this.identityStack.Add(entry.Id, entry.Entry);
                this.insertRefreshObject = entry.ResolvedObject;
            }
        }
Example #19
0
 /// <summary>
 /// Tries to read an entry.
 /// </summary>
 /// <param name="entry">The entry.</param>
 /// <returns>true if a value was read, otherwise false</returns>
 private bool TryReadEntry(out MaterializerEntry entry)
 {
     if (this.TryStartReadFeedOrEntry())
     {
         this.ExpectState(ODataReaderState.ResourceStart);
         entry = this.ReadEntryCore();
         return(true);
     }
     else
     {
         entry = default(MaterializerEntry);
         return(false);
     }
 }
Example #20
0
        public void MaterializeComplexTypeShouldWork()
        {
            OData.ODataResource complexValue = new OData.ODataResource
            {
                Properties = new OData.ODataProperty[]
                {
                    new OData.ODataProperty {
                        Name = "age", Value = 11
                    },
                    new OData.ODataProperty {
                        Name = "name", Value = "June"
                    },
                    new OData.ODataProperty {
                        Name = "color", Value = new OData.ODataEnumValue("blue")
                    },
                    new OData.ODataProperty
                    {
                        Name  = "primitives",
                        Value = new OData.ODataCollectionValue
                        {
                            TypeName = "Edm.Int32",
                            Items    = new List <object> {
                                1, 2, 3
                            }
                        }
                    },
                    new OData.ODataProperty
                    {
                        Name  = "enums",
                        Value = new OData.ODataCollectionValue
                        {
                            TypeName = "color",
                            Items    = new List <OData.ODataEnumValue> {
                                new OData.ODataEnumValue("white"), new OData.ODataEnumValue("blue")
                            }
                        }
                    }
                }
            };
            var materializerEntry = MaterializerEntry.CreateEntry(complexValue, OData.ODataFormat.Json, false, new ClientEdmModel(ODataProtocolVersion.V4));

            this.CreateEntryMaterializationPolicy().Materialize(materializerEntry, typeof(ComplexType), false);
            var complex = materializerEntry.ResolvedObject as ComplexType;

            complex.Name.Should().Be("June");
            complex.Age.Should().Be(11);
            complex.Color.Should().Be(Color.Blue);
            complex.Primitives.Should().ContainInOrder(1, 2, 3);
            complex.Enums.Should().ContainInOrder(Color.White, Color.Blue);
        }
Example #21
0
        /// <summary>
        /// Invoke this method to notify the log that a new instance
        /// was created.
        /// </summary>
        /// <param name="entry">Entry for the created instance.</param>
        internal void CreatedInstance(MaterializerEntry entry)
        {
            Debug.Assert(entry.Entry != null, "entry != null");
            Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise, what did we create?");
            Debug.Assert(entry.CreatedByMaterializer, "entry.CreatedByMaterializer -- otherwise we shouldn't be calling this");

            if (IsEntity(entry) && entry.IsTracking && !entry.Entry.IsTransient)
            {
                this.identityStack.Add(entry.Id, entry.Entry);
                if (this.mergeOption == MergeOption.AppendOnly)
                {
                    this.appendOnlyEntries.Add(entry.Id, entry.Entry);
                }
            }
        }
Example #22
0
        private ODataEntry CreateEntryWithMaterializerEntry(ODataFormat format, object resolvedObject)
        {
            var entry = new ODataEntry();

            entry.Id         = new Uri("http://www.odata.org/Northwind.Svc/Customer(1)");
            entry.Properties = new ODataProperty[] { new ODataProperty()
                                                     {
                                                         Name = "ID", Value = 1
                                                     } };

            var materializerEntry = MaterializerEntry.CreateEntry(entry, format, true, this.clientModel);

            materializerEntry.ResolvedObject = resolvedObject;

            return(entry);
        }
Example #23
0
        /// <summary>
        /// Invoke this method to notify the log that a new link was
        /// added to a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection to which <paramref name="target"/>
        /// was added.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was added.</param>
        internal void AddedLink(MaterializerEntry source, string propertyName, object target)
        {
            Debug.Assert(source.Entry != null || source.ForLoadProperty, "source != null || source.ForLoadProperty");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (!this.Tracking)
            {
                return;
            }

            if (IsEntity(source) && IsEntity(target, this.clientEdmModel))
            {
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added);
                this.links.Add(item);
            }
        }
Example #24
0
        /// <summary>
        /// Populates the collection property on the entry's resolved object with the given items enumerator.
        /// </summary>
        /// <param name="entry">Entry with collection to be modified.</param>
        /// <param name="property">Collection property on the entry.</param>
        /// <param name="items">Values to apply onto the collection.</param>
        /// <param name="nextLink">Next link for collection continuation.</param>
        /// <param name="continuationPlan">Projection plan for collection continuation.</param>
        /// <returns>Collection instance that was populated.</returns>
        private object PopulateCollectionProperty(
            MaterializerEntry entry,
            ClientPropertyAnnotation property,
            IEnumerable <object> items,
            Uri nextLink,
            ProjectionPlan continuationPlan)
        {
            Debug.Assert(entry.Entry != null || entry.ForLoadProperty, "ODataResource should be non-null except for LoadProperty");
            Debug.Assert(property != null, "property != null");
            Debug.Assert(items != null, "items != null");

            object collection = null;

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

            if (entry.ShouldUpdateFromPayload)
            {
                collection = this.GetOrCreateCollectionProperty(entry.ResolvedObject, property, entry.ForLoadProperty);

                foreach (object item in items)
                {
                    // Validate that item can be inserted into collection.
                    ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType);

                    property.SetValue(collection, item, property.PropertyName, true /* allowAdd? */);

                    this.EntityTrackingAdapter.MaterializationLog.AddedLink(entry, property.PropertyName, item);
                }

                this.FoundNextLinkForCollection(collection as IEnumerable, nextLink, continuationPlan);
            }
            else
            {
                Debug.Assert(!entry.ForLoadProperty, "LoadProperty should always have ShouldUpdateForPayload set to true.");

                foreach (object item in items)
                {
                    // Validate that item can be inserted into collection.
                    ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType);
                }

                this.FoundNextLinkForUnmodifiedCollection(property.GetValue(entry.ResolvedObject) as IEnumerable);
            }

            return(collection);
        }
Example #25
0
        /// <summary>"Resolved" the entity in the <paramref name="entry"/> by instantiating it.</summary>
        /// <param name="entry">Entry to resolve.</param>
        /// <param name="type">Type to create.</param>
        /// <remarks>
        /// After invocation, entry.ResolvedObject is exactly of type <paramref name="type"/>.
        /// </remarks>
        internal void ResolveByCreatingWithType(MaterializerEntry entry, Type type)
        {
            // TODO: CreateNewInstance needs to do all of these operations otherwise an inadvertent call to CreateNewInstance
            // will create a new entity instance that is not tracked in the context or materialization log. Will need to change this
            // prior to shipping if public
            Debug.Assert(
                entry.ResolvedObject == null,
                "entry.ResolvedObject == null -- otherwise we're about to overwrite - should never be called");
            ClientEdmModel edmModel = this.MaterializerContext.Model;

            entry.ActualType              = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(type));
            entry.ResolvedObject          = this.CreateNewInstance(entry.ActualType.EdmTypeReference, type);
            entry.CreatedByMaterializer   = true;
            entry.ShouldUpdateFromPayload = true;
            entry.EntityHasBeenResolved   = true;
            this.EntityTrackingAdapter.MaterializationLog.CreatedInstance(entry);
        }
Example #26
0
        public void AfterEntryMaterializedShouldOccur()
        {
            foreach (ODataFormat format in new ODataFormat[] { ODataFormat.Atom, ODataFormat.Json })
            {
                var entity = new SimpleEntity()
                {
                    ID = 1
                };
                var odataEntry = CreateEntryWithMaterializerEntry(format, entity);
                MaterializedEntityArgs found = null;
                this.context.Configurations.ResponsePipeline.OnEntityMaterialized((MaterializedEntityArgs materializedEntryEventArgs) => found = materializedEntryEventArgs);

                this.context.Configurations.ResponsePipeline.FireEndEntryEvents(MaterializerEntry.GetEntry(odataEntry));
                Assert.IsNotNull(found);
                found.Entity.Should().Be(entity);
                found.Entry.Should().Be(odataEntry);
            }
        }
Example #27
0
        /// <summary>Resolved or creates an instance on the specified <paramref name="entry"/>.</summary>
        /// <param name="entry">Entry on which to resolve or create an instance.</param>
        /// <param name="expectedEntryType">Expected type for the <paramref name="entry"/>.</param>
        /// <remarks>
        /// After invocation, the ResolvedObject value of the <paramref name="entry"/>
        /// will be assigned, along with the ActualType value.
        /// </remarks>
        /// <returns>True if an existing entity is found.</returns>
        internal virtual bool TryResolveExistingEntity(MaterializerEntry entry, Type expectedEntryType)
        {
            Debug.Assert(entry.Entry != null, "entry != null");
            Debug.Assert(expectedEntryType != null, "expectedEntryType != null");
            Debug.Assert(entry.EntityHasBeenResolved == false, "entry.EntityHasBeenResolved == false");

            // This will be the case when TargetInstance has been set.
            if (this.TryResolveAsTarget(entry))
            {
                return(true);
            }

            if (this.TryResolveAsExistingEntry(entry, expectedEntryType))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// This method is for parsing CUD operation payloads which should contain
        /// 1 a single entry
        /// 2 An Error
        /// </summary>
        /// <param name="message">the message for the payload</param>
        /// <param name="responseInfo">The current ResponseInfo object</param>
        /// <param name="expectedType">The expected type</param>
        /// <returns>the MaterializerEntry that was read</returns>
        internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType)
        {
            ODataPayloadKind messageType = ODataPayloadKind.Resource;

            using (ODataMessageReader messageReader = CreateODataMessageReader(message, responseInfo, ref messageType))
            {
                IEdmType           edmType = responseInfo.TypeResolver.ResolveExpectedTypeForReading(expectedType);
                ODataReaderWrapper reader  = ODataReaderWrapper.Create(messageReader, messageType, edmType, responseInfo.ResponsePipeline);

                FeedAndEntryMaterializerAdapter parser = new FeedAndEntryMaterializerAdapter(messageReader, reader, responseInfo.Model, responseInfo.MergeOption);

                ODataResource entry    = null;
                bool          readFeed = false;
                while (parser.Read())
                {
                    readFeed |= parser.CurrentFeed != null;
                    if (parser.CurrentEntry != null)
                    {
                        if (entry != null)
                        {
                            throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_MultipleFound);
                        }

                        entry = parser.CurrentEntry;
                    }
                }

                if (entry == null)
                {
                    if (readFeed)
                    {
                        throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_NoneFound);
                    }
                    else
                    {
                        throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_ExpectedFeedOrEntry);
                    }
                }

                return(MaterializerEntry.GetEntry(entry));
            }
        }
Example #29
0
        private void HandleOperationResponseData(HttpWebResponse response, Stream responseStream)
        {
            Version       version;
            Func <Stream> getResponseStream     = null;
            Dictionary <string, string> headers = WebUtil.WrapResponseHeaders(response);
            Descriptor        descriptor        = base.ChangedEntries[base.entryIndex];
            MaterializerEntry entry             = null;
            Exception         exception         = BaseSaveResult.HandleResponse(base.RequestInfo, response.StatusCode, response.Headers["DataServiceVersion"], () => responseStream, false, out version);

            if (((responseStream != null) && (descriptor.DescriptorKind == DescriptorKind.Entity)) && (exception == null))
            {
                EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;
                if (((entityDescriptor.State == EntityStates.Added) || (entityDescriptor.StreamState == EntityStates.Added)) || ((entityDescriptor.State == EntityStates.Modified) || (entityDescriptor.StreamState == EntityStates.Modified)))
                {
                    try
                    {
                        ResponseInfo responseInfo = base.CreateResponseInfo(entityDescriptor);
                        if (getResponseStream == null)
                        {
                            getResponseStream = () => responseStream;
                        }
                        HttpWebResponseMessage message = new HttpWebResponseMessage(response, getResponseStream);
                        entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(message, responseInfo, entityDescriptor.Entity.GetType());
                        entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor;
                    }
                    catch (Exception exception2)
                    {
                        exception = exception2;
                        if (!CommonUtil.IsCatchableExceptionType(exception2))
                        {
                            throw;
                        }
                    }
                }
            }
            this.cachedResponses.Add(new CachedResponse(descriptor, headers, response.StatusCode, version, (entry != null) ? entry.Entry : null, exception));
            if (exception != null)
            {
                descriptor.SaveError = exception;
            }
        }
Example #30
0
        private void TestApplyItemsToCollection(
            TestCustomer customer,
            IEnumerable orders,
            MergeOption option,
            TestEntityTracker entityTracker,
            bool isContinuation)
        {
            var customerDescriptor = new EntityDescriptor(this.clientEdmModel)
            {
                Entity = customer
            };

            var materializerEntry = MaterializerEntry.CreateEntryForLoadProperty(customerDescriptor, ODataFormat.Json, true);

            materializerEntry.ActualType = this.clientEdmModel.GetClientTypeAnnotation(clientEdmModel.GetOrCreateEdmType(typeof(TestCustomer)));

            var adapter = new EntityTrackingAdapter(
                entityTracker,
                option,
                clientEdmModel,
                new DataServiceContext());

            EntryValueMaterializationPolicy evmp = new EntryValueMaterializationPolicy(
                materializerContext,
                adapter,
                null,
                new Dictionary <IEnumerable, DataServiceQueryContinuation>());

            evmp.ApplyItemsToCollection(
                materializerEntry,
                ordersProperty,
                orders,
                null,
                null,
                isContinuation);

            if (entityTracker.GetEntityDescriptorFunc != null)
            {
                adapter.MaterializationLog.ApplyToContext();
            }
        }