/// <summary>Initializes a projection-driven entry (with a specific type and specific properties).</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="resultType">Expected result type.</param> /// <param name="properties">Properties to materialize.</param> /// <param name="propertyValues">Functions to get values for functions.</param> /// <returns>The initialized entry.</returns> internal static object ProjectionInitializeEntity( object materializer, object entry, Type expectedType, Type resultType, string[] properties, Func <object, object, Type, object>[] propertyValues) { Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())"); Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)"); return(ODataEntityMaterializer.ProjectionInitializeEntity((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataResource)entry), expectedType, resultType, properties, propertyValues)); }
/// <summary>Materializes an entry without including in-lined expanded links.</summary> /// <param name="materializer">Materializer under which materialization should take place.</param> /// <param name="entry">Entry with object to materialize.</param> /// <param name="expectedEntryType">Expected type for the entry.</param> /// <returns>The materialized instance.</returns> internal static object ShallowMaterializePlan(object materializer, object entry, Type expectedEntryType) { Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())"); Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)"); return(ODataEntityMaterializer.ShallowMaterializePlan((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataResource)entry), expectedEntryType)); }
/// <summary>Applies all accumulated changes to the associated data context.</summary> /// <remarks>The log should be cleared after this method successfully executed.</remarks> internal void ApplyToContext() { if (!this.Tracking) { return; } foreach (KeyValuePair <Uri, ODataResource> entity in this.identityStack) { // Try to attach the entity descriptor got from materializer, if one already exists, get the existing reference instead. MaterializerEntry entry = MaterializerEntry.GetEntry(entity.Value); bool mergeEntityDescriptorInfo = entry.CreatedByMaterializer || entry.ResolvedObject == this.insertRefreshObject || entry.ShouldUpdateFromPayload; // Whenever we merge the data, only at those times will be merge the links also EntityDescriptor descriptor = this.entityTracker.InternalAttachEntityDescriptor(entry.EntityDescriptor, false /*failIfDuplicated*/); AtomMaterializerLog.MergeEntityDescriptorInfo(descriptor, entry.EntityDescriptor, mergeEntityDescriptorInfo, this.mergeOption); if (mergeEntityDescriptorInfo) { // In AtomMaterializer.TryResolveFromContext, we set AtomEntry.ShouldUpdateFromPayload to true // when even MergeOption is PreserveChanges and entityState is Deleted. But in that case, we cannot // set the entity state to Unchanged, hence need to workaround that one scenario if (this.mergeOption != MergeOption.PreserveChanges || descriptor.State != EntityStates.Deleted) { // we should always reset descriptor's state to Unchanged (old v1 behavior) descriptor.State = EntityStates.Unchanged; descriptor.PropertiesToSerialize.Clear(); } } } foreach (LinkDescriptor link in this.links) { if (EntityStates.Added == link.State) { // Added implies collection this.entityTracker.AttachLink(link.Source, link.SourceProperty, link.Target, this.mergeOption); } else if (EntityStates.Modified == link.State) { // Modified implies reference object target = link.Target; if (MergeOption.PreserveChanges == this.mergeOption) { // GetLinks looks up the existing link using just the SourceProperty, the declaring server type name is not significant here. LinkDescriptor end = this.entityTracker.GetLinks(link.Source, link.SourceProperty).SingleOrDefault(); if (end != null && end.Target == null) { // leave the SetLink(link.Source, link.SourceProperty, null) continue; } if ((target != null) && (this.entityTracker.GetEntityDescriptor(target).State == EntityStates.Deleted) || (EntityStates.Deleted == this.entityTracker.GetEntityDescriptor(link.Source).State)) { target = null; } } this.entityTracker.AttachLink(link.Source, link.SourceProperty, target, this.mergeOption); } else { // detach link Debug.Assert(EntityStates.Detached == link.State, "not detached link"); this.entityTracker.DetachExistingLink(link, false); } } }