/// <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)); }
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)); }
/// <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); }
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); }
/// <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); }
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); } }
/// <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); } }
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)); }
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 :; } } } }
/// <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); }
/// <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); }
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)); }
/// <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); } }
/// <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; }
/// <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; } }
/// <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); } }
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); }
/// <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); } } }
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); }
/// <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); } }
/// <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); }
/// <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); }
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); } }
/// <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)); } }
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; } }
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(); } }