From 7f2f53992d7d9a02daf3f01adaa97d31fbf2162a Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Fri, 9 Sep 2022 22:51:14 +0300
Subject: [PATCH 01/16] Replace ConditionalWeakTable with
 MaterializerContext.AnnotationsCache

---
 .../AtomMaterializerLog.cs                    | 11 +++--
 .../CollectionValueMaterializationPolicy.cs   |  2 +-
 .../Materialization/EntityTrackingAdapter.cs  |  4 +-
 .../EntryValueMaterializationPolicy.cs        | 14 +++---
 .../EnumValueMaterializationPolicy.cs         |  4 +-
 .../FeedAndEntryMaterializerAdapter.cs        | 24 +++++-----
 .../IODataMaterializerContext.cs              |  2 +
 .../MaterializerAnnotationsCache.cs           | 44 +++++++++++++++++++
 .../Materialization/MaterializerEntry.cs      | 10 ++---
 .../Materialization/MaterializerFeed.cs       | 10 ++---
 .../MaterializerNavigationLink.cs             | 16 +++----
 .../ODataEntityMaterializer.cs                | 34 +++++++-------
 .../ODataEntityMaterializerInvoker.cs         | 27 +++++++-----
 .../Materialization/ODataItemExtensions.cs    | 24 +++++-----
 .../Materialization/ODataMaterializer.cs      |  2 +-
 .../ODataMaterializerContext.cs               |  3 ++
 .../ODataReaderEntityMaterializer.cs          |  8 ++--
 .../StructuralValueMaterializationPolicy.cs   |  6 +--
 .../MaterializeFromAtom.cs                    |  2 +-
 .../ODataAnnotatableExtensions.cs             | 32 +++++++-------
 src/Microsoft.OData.Client/SaveResult.cs      |  3 +-
 21 files changed, 174 insertions(+), 108 deletions(-)
 create mode 100644 src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs

diff --git a/src/Microsoft.OData.Client/AtomMaterializerLog.cs b/src/Microsoft.OData.Client/AtomMaterializerLog.cs
index 6a89587bbf..0b79b25428 100644
--- a/src/Microsoft.OData.Client/AtomMaterializerLog.cs
+++ b/src/Microsoft.OData.Client/AtomMaterializerLog.cs
@@ -46,6 +46,8 @@ internal class AtomMaterializerLog
         /// <summary>Target instance to refresh.</summary>
         private object insertRefreshObject;
 
+        private IODataMaterializerContext materializerContext;
+
         #endregion Private fields
 
         #region Constructors
@@ -59,7 +61,7 @@ internal class AtomMaterializerLog
         /// <remarks>
         /// Note that the merge option can't be changed.
         /// </remarks>
-        internal AtomMaterializerLog(MergeOption mergeOption, ClientEdmModel model, EntityTrackerBase entityTracker)
+        internal AtomMaterializerLog(MergeOption mergeOption, ClientEdmModel model, EntityTrackerBase entityTracker, IODataMaterializerContext materializerContext)
         {
             Debug.Assert(model != null, "model != null");
             Debug.Assert(entityTracker != null, "entityTracker != null");
@@ -70,6 +72,7 @@ internal AtomMaterializerLog(MergeOption mergeOption, ClientEdmModel model, Enti
             this.entityTracker = entityTracker;
             this.identityStack = new Dictionary<Uri, ODataResource>(EqualityComparer<Uri>.Default);
             this.links = new List<LinkDescriptor>();
+            this.materializerContext = materializerContext;
         }
 
         #endregion Constructors
@@ -179,7 +182,7 @@ internal void ApplyToContext()
             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);
+                MaterializerEntry entry = MaterializerEntry.GetEntry(entity.Value, this.materializerContext);
 
                 bool mergeEntityDescriptorInfo = entry.CreatedByMaterializer ||
                                                  entry.ResolvedObject == this.insertRefreshObject ||
@@ -309,7 +312,7 @@ internal bool TryResolve(MaterializerEntry entry, out MaterializerEntry existing
 
             if (this.identityStack.TryGetValue(entry.Id, out existingODataEntry))
             {
-                existingEntry = MaterializerEntry.GetEntry(existingODataEntry);
+                existingEntry = MaterializerEntry.GetEntry(existingODataEntry, this.materializerContext);
                 return true;
             }
 
@@ -321,7 +324,7 @@ internal bool TryResolve(MaterializerEntry entry, out MaterializerEntry existing
                 this.entityTracker.TryGetEntity(entry.Id, out state);
                 if (state == EntityStates.Unchanged)
                 {
-                    existingEntry = MaterializerEntry.GetEntry(existingODataEntry);
+                    existingEntry = MaterializerEntry.GetEntry(existingODataEntry, this.materializerContext);
                     return true;
                 }
                 else
diff --git a/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
index 5406d6234e..dd559d54ce 100644
--- a/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
@@ -134,7 +134,7 @@ internal void ApplyCollectionDataValues(
                 addValueToBackingICollectionInstance,
                 isElementNullable);
 
-            collectionProperty.SetMaterializedValue(collectionInstance);
+            collectionProperty.SetMaterializedValue(collectionInstance, this.materializerContext);
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
index 1a68c1ee68..be2e6e2bbf 100644
--- a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
+++ b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
@@ -27,9 +27,9 @@ internal class EntityTrackingAdapter
         /// <param name="mergeOption">The merge option.</param>
         /// <param name="model">The model.</param>
         /// <param name="context">The context.</param>
-        internal EntityTrackingAdapter(EntityTrackerBase entityTracker, MergeOption mergeOption, ClientEdmModel model, DataServiceContext context)
+        internal EntityTrackingAdapter(EntityTrackerBase entityTracker, MergeOption mergeOption, ClientEdmModel model, DataServiceContext context, IODataMaterializerContext materializerContext)
         {
-            this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker);
+            this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker, materializerContext);
             this.MergeOption = mergeOption;
             this.EntityTracker = entityTracker;
             this.Model = model;
diff --git a/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
index 7172a50738..1d58a28020 100644
--- a/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
@@ -534,11 +534,11 @@ private void ApplyFeedToCollection(
             ClientEdmModel edmModel = this.MaterializerContext.Model;
             ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType));
 
-            IEnumerable<ODataResource> entries = MaterializerFeed.GetFeed(feed).Entries;
+            IEnumerable<ODataResource> entries = MaterializerFeed.GetFeed(feed, this.MaterializerContext).Entries;
 
             foreach (ODataResource feedEntry in entries)
             {
-                this.Materialize(MaterializerEntry.GetEntry(feedEntry), collectionType.ElementType, includeLinks);
+                this.Materialize(MaterializerEntry.GetEntry(feedEntry, this.MaterializerContext), collectionType.ElementType, includeLinks);
             }
 
             ProjectionPlan continuationPlan = includeLinks ?
@@ -548,7 +548,7 @@ private void ApplyFeedToCollection(
             this.ApplyItemsToCollection(
                 entry,
                 property,
-                entries.Select(e => MaterializerEntry.GetEntry(e).ResolvedObject),
+                entries.Select(e => MaterializerEntry.GetEntry(e, this.MaterializerContext).ResolvedObject),
                 feed.NextPageLink,
                 continuationPlan,
                 false);
@@ -591,7 +591,7 @@ private void MaterializeResolvedEntry(MaterializerEntry entry, bool includeLinks
 
                 foreach (ODataNestedResourceInfo link in entry.NestedResourceInfos)
                 {
-                    MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link);
+                    MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link, this.MaterializerContext);
 
                     if (linkState == null)
                     {
@@ -722,7 +722,7 @@ private void MaterializeDynamicProperty(MaterializerEntry entry, ODataNestedReso
                 return;
             }
 
-            MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link);
+            MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link, this.MaterializerContext);
             if (linkState == null || (linkState.Entry == null && linkState.Feed == null))
             {
                 return;
@@ -754,10 +754,10 @@ private void MaterializeDynamicProperty(MaterializerEntry entry, ODataNestedReso
                     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;
+                    IEnumerable<ODataResource> feedEntries = MaterializerFeed.GetFeed(linkState.Feed, this.MaterializerContext).Entries;
                     foreach (ODataResource feedEntry in feedEntries)
                     {
-                        MaterializerEntry linkEntry = MaterializerEntry.GetEntry(feedEntry);
+                        MaterializerEntry linkEntry = MaterializerEntry.GetEntry(feedEntry, this.MaterializerContext);
                         this.Materialize(linkEntry, collectionItemType, false /*includeLinks*/);
                         collection.Add(linkEntry.ResolvedObject);
                     }
diff --git a/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
index 21975e8160..e5a6f5e314 100644
--- a/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
@@ -40,9 +40,9 @@ public object MaterializeEnumTypeProperty(Type valueType, ODataProperty property
             object materializedValue = null;
             ODataEnumValue value = property.Value as ODataEnumValue;
             this.MaterializeODataEnumValue(valueType, value.TypeName, value.Value, () => "TODO: Is this reachable?", out materializedValue);
-            if (!property.HasMaterializedValue())
+            if (!property.HasMaterializedValue(this.context))
             {
-                property.SetMaterializedValue(materializedValue);
+                property.SetMaterializedValue(materializedValue, this.context);
             }
 
             return materializedValue;
diff --git a/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs b/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
index 88a9e5dbf3..19815f4299 100644
--- a/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
+++ b/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
@@ -39,6 +39,8 @@ internal class FeedAndEntryMaterializerAdapter
         /// <summary>The current entry.</summary>
         private ODataResource currentEntry;
 
+        private IODataMaterializerContext materializerContext;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="FeedAndEntryMaterializerAdapter"/> class.
         /// </summary>
@@ -46,8 +48,8 @@ internal class FeedAndEntryMaterializerAdapter
         /// <param name="reader">The reader.</param>
         /// <param name="model">The model.</param>
         /// <param name="mergeOption">The mergeOption.</param>
-        internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption)
-            : this(ODataUtils.GetReadFormat(messageReader), reader, model, mergeOption)
+        internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption, IODataMaterializerContext materializerContext)
+            : this(ODataUtils.GetReadFormat(messageReader), reader, model, mergeOption, materializerContext)
         {
         }
 
@@ -58,7 +60,7 @@ internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, OData
         /// <param name="reader">The reader.</param>
         /// <param name="model">The model.</param>
         /// <param name="mergeOption">The mergeOption.</param>
-        internal FeedAndEntryMaterializerAdapter(ODataFormat odataFormat, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption)
+        internal FeedAndEntryMaterializerAdapter(ODataFormat odataFormat, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption, IODataMaterializerContext materializerContext)
         {
             this.readODataFormat = odataFormat;
             this.clientEdmModel = model;
@@ -67,6 +69,7 @@ internal FeedAndEntryMaterializerAdapter(ODataFormat odataFormat, ODataReaderWra
             this.currentEntry = null;
             this.currentFeed = null;
             this.feedEntries = null;
+            this.materializerContext = materializerContext;
         }
 
         /// <summary>
@@ -105,7 +108,7 @@ 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();
+                this.feedEntries = MaterializerFeed.GetFeed(this.currentFeed, this.materializerContext).Entries.GetEnumerator();
             }
 
             if (this.currentFeed != null && this.currentFeed.Count.HasValue)
@@ -152,7 +155,7 @@ public bool Read()
                             this.currentFeed = feed;
                             if (this.currentFeed != null)
                             {
-                                this.feedEntries = MaterializerFeed.GetFeed(this.currentFeed).Entries.GetEnumerator();
+                                this.feedEntries = MaterializerFeed.GetFeed(this.currentFeed, this.materializerContext).Entries.GetEnumerator();
 
                                 // Try to read the first entry.
                                 if (!this.feedEntries.MoveNext())
@@ -278,11 +281,11 @@ private ODataResourceSet ReadFeedCore(bool lazy)
 
             if (lazy)
             {
-                MaterializerFeed.CreateFeed(result, lazyEntries);
+                MaterializerFeed.CreateFeed(result, lazyEntries, this.materializerContext);
             }
             else
             {
-                MaterializerFeed.CreateFeed(result, new List<ODataResource>(lazyEntries));
+                MaterializerFeed.CreateFeed(result, new List<ODataResource>(lazyEntries), this.materializerContext);
             }
 
             return result;
@@ -339,7 +342,8 @@ private MaterializerEntry ReadEntryCore()
                     result,
                     this.readODataFormat,
                     this.mergeOption != MergeOption.NoTracking,
-                    this.clientEdmModel);
+                    this.clientEdmModel,
+                    this.materializerContext);
 
                 do
                 {
@@ -395,12 +399,12 @@ private ODataNestedResourceInfo ReadNestedResourceInfo()
             {
                 if (feed != null)
                 {
-                    MaterializerNavigationLink.CreateLink(link, feed);
+                    MaterializerNavigationLink.CreateLink(link, feed, this.materializerContext);
                 }
                 else
                 {
                     Debug.Assert(entry != null, "entry != null");
-                    MaterializerNavigationLink.CreateLink(link, entry);
+                    MaterializerNavigationLink.CreateLink(link, entry, this.materializerContext);
                 }
 
                 this.ReadAndExpectState(ODataReaderState.NestedResourceInfoEnd);
diff --git a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
index b28f50fe0b..edb4c7e90d 100644
--- a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
@@ -52,5 +52,7 @@ internal interface IODataMaterializerContext
         /// <param name="clientClrType">The client side CLR type.</param>
         /// <returns>The resolved EDM type to provide to ODataLib.</returns>
         IEdmType ResolveExpectedTypeForReading(Type clientClrType);
+
+        MaterializerAnnotationsCache AnnotationsCache { get;  }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
new file mode 100644
index 0000000000..1c14b2e349
--- /dev/null
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.OData.Client.Materialization
+{
+    internal class MaterializerAnnotationsCache
+    {
+        private readonly Dictionary<ODataAnnotatable, object> cache = new Dictionary<ODataAnnotatable, object>(ReferenceEqualityComparer<ODataAnnotatable>.Instance);
+
+        public void SetAnnotation<T>(ODataAnnotatable annotatable, T value) where T : class
+        {
+            this.cache.Add(annotatable, value);
+        }
+
+        public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
+        {
+            if (this.cache.TryGetValue(annotatable, out object value))
+            {
+                Debug.Assert(value is T);
+                return value as T;
+            }
+
+            return default(T);
+        }
+    }
+
+    internal static class MaterializerContextExtensions
+    {
+        public static void SetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable, T value) where T : class
+        {
+            context.AnnotationsCache.SetAnnotation(annotatable, value);
+        }
+
+        public static T GetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable) where T : class
+        {
+            return context.AnnotationsCache.GetAnnotation<T>(annotatable);
+        }
+    }
+}
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs b/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
index de815eae35..0106ea7ef8 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
@@ -225,12 +225,12 @@ public static MaterializerEntry CreateEmpty()
         /// <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)
+        public static MaterializerEntry CreateEntry(ODataResource entry, ODataFormat format, bool isTracking, ClientEdmModel model, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(entry.GetAnnotation<MaterializerEntry>() == null, "MaterializerEntry has already been created.");
+            Debug.Assert(materializerContext.GetAnnotation<MaterializerEntry>(entry) == null, "MaterializerEntry has already been created.");
 
             MaterializerEntry materializerEntry = new MaterializerEntry(entry, format, isTracking, model);
-            entry.SetAnnotation<MaterializerEntry>(materializerEntry);
+            materializerContext.SetAnnotation<MaterializerEntry>(entry, materializerEntry);
 
             return materializerEntry;
         }
@@ -252,9 +252,9 @@ public static MaterializerEntry CreateEntryForLoadProperty(EntityDescriptor desc
         /// </summary>
         /// <param name="entry">The ODataResource.</param>
         /// <returns>The materializer entry</returns>
-        public static MaterializerEntry GetEntry(ODataResource entry)
+        public static MaterializerEntry GetEntry(ODataResource entry, IODataMaterializerContext materializerContext)
         {
-            return entry.GetAnnotation<MaterializerEntry>();
+            return materializerContext.GetAnnotation<MaterializerEntry>(entry);
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs b/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
index b29940d832..adf624e3bf 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
@@ -68,16 +68,16 @@ public Uri NextPageLink
         /// <param name="feed">The feed.</param>
         /// <param name="entries">The entries.</param>
         /// <returns>The materializer feed.</returns>
-        public static MaterializerFeed CreateFeed(ODataResourceSet feed, IEnumerable<ODataResource> entries)
+        public static MaterializerFeed CreateFeed(ODataResourceSet feed, IEnumerable<ODataResource> entries, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(feed.GetAnnotation<IEnumerable<ODataResource>>() == null, "Feed state has already been created.");
+            Debug.Assert(materializerContext.GetAnnotation<IEnumerable<ODataResource>>(feed) == null, "Feed state has already been created.");
             if (entries == null)
             {
                 entries = Enumerable.Empty<ODataResource>();
             }
             else
             {
-                feed.SetAnnotation<IEnumerable<ODataResource>>(entries);
+                materializerContext.SetAnnotation<IEnumerable<ODataResource>>(feed, entries);
             }
 
             return new MaterializerFeed(feed, entries);
@@ -88,9 +88,9 @@ public static MaterializerFeed CreateFeed(ODataResourceSet feed, IEnumerable<ODa
         /// </summary>
         /// <param name="feed">The feed.</param>
         /// <returns>The materializer feed.</returns>
-        public static MaterializerFeed GetFeed(ODataResourceSet feed)
+        public static MaterializerFeed GetFeed(ODataResourceSet feed, IODataMaterializerContext materializerContext)
         {
-            IEnumerable<ODataResource> entries = feed.GetAnnotation<IEnumerable<ODataResource>>();
+            IEnumerable<ODataResource> entries = materializerContext.GetAnnotation<IEnumerable<ODataResource>>(feed);
             return new MaterializerFeed(feed, entries);
         }
     }
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs b/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
index 40ebd13752..ec4b360b14 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
@@ -64,11 +64,11 @@ public ODataResourceSet Feed
         /// <param name="link">The link.</param>
         /// <param name="entry">The entry.</param>
         /// <returns>The materializer link.</returns>
-        public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, MaterializerEntry entry)
+        public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, MaterializerEntry entry, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(link.GetAnnotation<MaterializerNavigationLink>() == null, "there should be no MaterializerNestedResourceInfo annotation on the entry link yet");
+            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null, "there should be no MaterializerNestedResourceInfo annotation on the entry link yet");
             MaterializerNavigationLink materializedNestedResourceInfo = new MaterializerNavigationLink(link, entry);
-            link.SetAnnotation<MaterializerNavigationLink>(materializedNestedResourceInfo);
+            materializerContext.SetAnnotation<MaterializerNavigationLink>(link, materializedNestedResourceInfo);
             return materializedNestedResourceInfo;
         }
 
@@ -78,11 +78,11 @@ public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link
         /// <param name="link">The link.</param>
         /// <param name="resourceSet">The resource set.</param>
         /// <returns>The materializer link.</returns>
-        public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, ODataResourceSet resourceSet)
+        public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, ODataResourceSet resourceSet, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(link.GetAnnotation<MaterializerNavigationLink>() == null, "there should be no MaterializerNestedResourceInfo annotation on the feed link yet");
+            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null, "there should be no MaterializerNestedResourceInfo annotation on the feed link yet");
             MaterializerNavigationLink materializedNestedResourceInfo = new MaterializerNavigationLink(link, resourceSet);
-            link.SetAnnotation<MaterializerNavigationLink>(materializedNestedResourceInfo);
+            materializerContext.SetAnnotation<MaterializerNavigationLink>(link, materializedNestedResourceInfo);
             return materializedNestedResourceInfo;
         }
 
@@ -91,9 +91,9 @@ public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link
         /// </summary>
         /// <param name="link">The link.</param>
         /// <returns>The materializer link.</returns>
-        public static MaterializerNavigationLink GetLink(ODataNestedResourceInfo link)
+        public static MaterializerNavigationLink GetLink(ODataNestedResourceInfo link, IODataMaterializerContext materializerContext)
         {
-            return link.GetAnnotation<MaterializerNavigationLink>();
+            return materializerContext.GetAnnotation<MaterializerNavigationLink>(link);
         }
     }
 }
\ No newline at end of file
diff --git a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
index 7b978fa569..384a0a5a4f 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
@@ -240,7 +240,8 @@ internal static ProjectionPlan CreatePlanForShallowMaterialization(Type lastSegm
         internal static bool ProjectionCheckValueForPathIsNull(
             MaterializerEntry entry,
             Type expectedType,
-            ProjectionPath path)
+            ProjectionPath path,
+            IODataMaterializerContext materializerContext)
         {
             Debug.Assert(path != null, "path != null");
 
@@ -279,7 +280,7 @@ internal static bool ProjectionCheckValueForPathIsNull(
 
                 IEdmType expectedEdmType = model.GetOrCreateEdmType(expectedType);
                 ClientPropertyAnnotation property = model.GetClientTypeAnnotation(expectedEdmType).GetProperty(propertyName, UndeclaredPropertyBehavior.ThrowException);
-                atomProperty = ODataEntityMaterializer.GetPropertyOrThrow(properties, propertyName);
+                atomProperty = ODataEntityMaterializer.GetPropertyOrThrow(properties, propertyName, materializerContext);
                 EntryValueMaterializationPolicy.ValidatePropertyMatch(property, atomProperty.Link);
                 if (atomProperty.Feed != null)
                 {
@@ -348,7 +349,7 @@ internal static IEnumerable ProjectionSelect(
 
                 // If we are projecting a property defined on a derived type and the entry is of the base type, get property would throw. The user need to check for null in the query.
                 // e.g. Select(p => new MyEmployee { ID = p.ID, Manager = (p as Employee).Manager == null ? null : new MyManager { ID = (p as Employee).Manager.ID } })
-                atomProperty = ODataEntityMaterializer.GetPropertyOrThrow(entry.NestedResourceInfos, propertyName);
+                atomProperty = ODataEntityMaterializer.GetPropertyOrThrow(entry.NestedResourceInfos, propertyName, materializer.MaterializerContext);
 
                 if (atomProperty.Entry != null)
                 {
@@ -358,7 +359,7 @@ internal static IEnumerable ProjectionSelect(
             }
 
             EntryValueMaterializationPolicy.ValidatePropertyMatch(property, atomProperty.Link);
-            MaterializerFeed sourceFeed = MaterializerFeed.GetFeed(atomProperty.Feed);
+            MaterializerFeed sourceFeed = MaterializerFeed.GetFeed(atomProperty.Feed, materializer.MaterializerContext);
             Debug.Assert(
                 sourceFeed.Feed != null,
                 "sourceFeed != null -- otherwise ValidatePropertyMatch should have thrown or property isn't a collection (and should be part of this plan)");
@@ -384,13 +385,13 @@ internal static IEnumerable ProjectionSelect(
         /// <param name="entry">Entry to get sub-entry from.</param>
         /// <param name="name">Name of sub-entry.</param>
         /// <returns>The sub-entry (never null).</returns>
-        internal static ODataResource ProjectionGetEntry(MaterializerEntry entry, string name)
+        internal static ODataResource ProjectionGetEntry(MaterializerEntry entry, string name, IODataMaterializerContext materializerContext)
         {
             Debug.Assert(entry.Entry != null, "entry != null -- ProjectionGetEntry never returns a null entry, and top-level materialization shouldn't pass one in");
 
             // If we are projecting a property defined on a derived type and the entry is of the base type, get property would throw. The user need to check for null in the query.
             // e.g. Select(p => new MyEmployee { ID = p.ID, Manager = (p as Employee).Manager == null ? null : new MyManager { ID = (p as Employee).Manager.ID } })
-            MaterializerNavigationLink property = ODataEntityMaterializer.GetPropertyOrThrow(entry.NestedResourceInfos, name);
+            MaterializerNavigationLink property = ODataEntityMaterializer.GetPropertyOrThrow(entry.NestedResourceInfos, name, materializerContext);
             MaterializerEntry result = property.Entry;
             if (result == null)
             {
@@ -662,11 +663,11 @@ internal object ProjectionValueForPath(MaterializerEntry entry, Type expectedTyp
                     {
                         EntryValueMaterializationPolicy.ValidatePropertyMatch(property, link);
 
-                        MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link);
+                        MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link, this.MaterializerContext);
 
                         if (linkState.Feed != null)
                         {
-                            MaterializerFeed feedValue = MaterializerFeed.GetFeed(linkState.Feed);
+                            MaterializerFeed feedValue = MaterializerFeed.GetFeed(linkState.Feed, this.MaterializerContext);
 
                             Debug.Assert(segmentIsLeaf, "segmentIsLeaf -- otherwise the path generated traverses a feed, which should be disallowed");
 
@@ -689,7 +690,7 @@ internal object ProjectionValueForPath(MaterializerEntry entry, Type expectedTyp
                             }
 
                             IEnumerable list = (IEnumerable)Util.ActivatorCreateInstance(feedType);
-                            MaterializeToList(this, list, nestedExpectedType, feedValue.Entries);
+                            MaterializeToList(this, list, nestedExpectedType, feedValue.Entries, this.MaterializerContext);
 
                             if (ClientTypeUtil.IsDataServiceCollection(segment.ProjectionType))
                             {
@@ -786,7 +787,7 @@ internal object ProjectionValueForPath(MaterializerEntry entry, Type expectedTyp
                             properties = ODataMaterializer.EmptyProperties;
                         }
 
-                        result = odataProperty.GetMaterializedValue();
+                        result = odataProperty.GetMaterializedValue(this.MaterializerContext);
 
                         // TODO: projection with anonymous type is not supported now.
                         // apply instance annotation for property
@@ -847,7 +848,7 @@ internal object ProjectionDynamicValueForPath(MaterializerEntry entry, Type expe
 
                 this.entryValueMaterializationPolicy.MaterializePrimitiveDataValue(expectedPropertyType, odataProperty);
 
-                return odataProperty.GetMaterializedValue();
+                return odataProperty.GetMaterializedValue(this.MaterializerContext);
             }
 
             return result;
@@ -903,7 +904,7 @@ protected override bool ReadImplementation()
 
                 Debug.Assert(this.CurrentEntry != null, "Read successfully without finding an entry.");
 
-                MaterializerEntry entryAndState = MaterializerEntry.GetEntry(this.CurrentEntry);
+                MaterializerEntry entryAndState = MaterializerEntry.GetEntry(this.CurrentEntry, this.MaterializerContext);
                 entryAndState.ResolvedObject = this.TargetInstance;
                 this.currentValue = this.materializeEntryPlan.Run(this, this.CurrentEntry, this.ExpectedType);
 
@@ -998,7 +999,8 @@ private static void MaterializeToList(
             ODataEntityMaterializer materializer,
             IEnumerable list,
             Type nestedExpectedType,
-            IEnumerable<ODataResource> entries)
+            IEnumerable<ODataResource> entries,
+            IODataMaterializerContext materializerContext)
         {
             Debug.Assert(materializer != null, "materializer != null");
             Debug.Assert(list != null, "list != null");
@@ -1006,7 +1008,7 @@ private static void MaterializeToList(
             Action<object, object> addMethod = ClientTypeUtil.GetAddToCollectionDelegate(list.GetType());
             foreach (ODataResource feedEntry in entries)
             {
-                MaterializerEntry feedEntryState = MaterializerEntry.GetEntry(feedEntry);
+                MaterializerEntry feedEntryState = MaterializerEntry.GetEntry(feedEntry, materializerContext);
                 if (!feedEntryState.EntityHasBeenResolved)
                 {
                     materializer.EntryValueMaterializationPolicy.Materialize(feedEntryState, nestedExpectedType, /* includeLinks */ false);
@@ -1020,7 +1022,7 @@ private static void MaterializeToList(
         /// <param name="links">List to get value from.</param>
         /// <param name="propertyName">Property name to look up.</param>
         /// <returns>The specified property (never null).</returns>
-        private static MaterializerNavigationLink GetPropertyOrThrow(IEnumerable<ODataNestedResourceInfo> links, string propertyName)
+        private static MaterializerNavigationLink GetPropertyOrThrow(IEnumerable<ODataNestedResourceInfo> links, string propertyName, IODataMaterializerContext materializerContext)
         {
             ODataNestedResourceInfo link = null;
             if (links != null)
@@ -1033,7 +1035,7 @@ private static MaterializerNavigationLink GetPropertyOrThrow(IEnumerable<ODataNe
                 throw new InvalidOperationException(DSClient.Strings.AtomMaterializer_PropertyMissing(propertyName));
             }
 
-            return MaterializerNavigationLink.GetLink(link);
+            return MaterializerNavigationLink.GetLink(link, materializerContext);
         }
 
         /// <summary>Merges a list into the property of a given <paramref name="entry"/>.</summary>
diff --git a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
index dc79df58ed..046ef198c7 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
@@ -59,11 +59,12 @@ internal static List<TTarget> ListAsElementType<T, TTarget>(object materializer,
         internal static bool ProjectionCheckValueForPathIsNull(
             object entry,
             Type expectedType,
-            object path)
+            object path,
+            IODataMaterializerContext materializerContext)
         {
             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);
+            return ODataEntityMaterializer.ProjectionCheckValueForPathIsNull(MaterializerEntry.GetEntry((ODataResource)entry, materializerContext), expectedType, (ProjectionPath)path, materializerContext);
         }
 
         /// <summary>Provides support for Select invocations for projections.</summary>
@@ -85,17 +86,18 @@ internal static IEnumerable ProjectionSelect(
             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.ProjectionSelect((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataResource)entry), expectedType, resultType, (ProjectionPath)path, selector);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return ODataEntityMaterializer.ProjectionSelect(entityMaterializer, MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedType, resultType, (ProjectionPath)path, selector);
         }
 
         /// <summary>Provides support for getting payload entries during projections.</summary>
         /// <param name="entry">Entry to get sub-entry from.</param>
         /// <param name="name">Name of sub-entry.</param>
         /// <returns>The sub-entry (never null).</returns>
-        internal static object ProjectionGetEntry(object entry, string name)
+        internal static object ProjectionGetEntry(object entry, string name, IODataMaterializerContext materializerContext)
         {
             Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)");
-            return ODataEntityMaterializer.ProjectionGetEntry(MaterializerEntry.GetEntry((ODataResource)entry), name);
+            return ODataEntityMaterializer.ProjectionGetEntry(MaterializerEntry.GetEntry((ODataResource)entry, materializerContext), name, materializerContext);
         }
 
         /// <summary>Initializes a projection-driven entry (with a specific type and specific properties).</summary>
@@ -116,7 +118,8 @@ internal static object ProjectionInitializeEntity(
         {
             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);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return ODataEntityMaterializer.ProjectionInitializeEntity(entityMaterializer, MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedType, resultType, properties, propertyValues);
         }
 
         /// <summary>Projects a simple value from the specified <paramref name="path"/>.</summary>
@@ -134,7 +137,8 @@ internal static object ProjectionValueForPath(object materializer, object entry,
             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);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return entityMaterializer.ProjectionValueForPath(MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedType, (ProjectionPath)path);
         }
 
         /// <summary>Projects a simple dynamic value from the specified <paramref name="path"/>.</summary>
@@ -152,7 +156,8 @@ internal static object ProjectionDynamicValueForPath(object materializer, object
             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).ProjectionDynamicValueForPath(MaterializerEntry.GetEntry((ODataResource)entry), expectedPropertyType, (ProjectionPath)path);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return entityMaterializer.ProjectionDynamicValueForPath(MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedPropertyType, (ProjectionPath)path);
         }
 
         /// <summary>Materializes an entry with no special selection.</summary>
@@ -164,7 +169,8 @@ internal static object DirectMaterializePlan(object materializer, object entry,
         {
             Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())");
             Debug.Assert(entry.GetType() == typeof(ODataResource), "entry.GetType() == typeof(ODataResource)");
-            return ODataEntityMaterializer.DirectMaterializePlan((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataResource)entry), expectedEntryType);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return ODataEntityMaterializer.DirectMaterializePlan(entityMaterializer, MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedEntryType);
         }
 
         /// <summary>Materializes an entry without including in-lined expanded links.</summary>
@@ -176,7 +182,8 @@ internal static object ShallowMaterializePlan(object materializer, object entry,
         {
             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);
+            ODataEntityMaterializer entityMaterializer = (ODataEntityMaterializer)materializer;
+            return ODataEntityMaterializer.ShallowMaterializePlan(entityMaterializer, MaterializerEntry.GetEntry((ODataResource)entry, entityMaterializer.MaterializerContext), expectedEntryType);
         }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
index e02c408524..713b2673e7 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
@@ -19,10 +19,10 @@ internal static class ODataItemExtensions
         /// </summary>
         /// <param name="property">The property.</param>
         /// <returns>The materialized value.</returns>
-        public static object GetMaterializedValue(this ODataProperty property)
+        public static object GetMaterializedValue(this ODataProperty property, IODataMaterializerContext materializerContext)
         {
             ODataAnnotatable annotatableObject = property.Value as ODataAnnotatable ?? property;
-            return GetMaterializedValueCore(annotatableObject);
+            return GetMaterializedValueCore(annotatableObject, materializerContext);
         }
 
         /// <summary>
@@ -30,10 +30,10 @@ public static object GetMaterializedValue(this ODataProperty property)
         /// </summary>
         /// <param name="property">The property.</param>
         /// <returns><c>true</c> if the value has been materialized; otherwise, <c>false</c>.</returns>
-        public static bool HasMaterializedValue(this ODataProperty property)
+        public static bool HasMaterializedValue(this ODataProperty property, IODataMaterializerContext materializerContext)
         {
             ODataAnnotatable annotatableObject = property.Value as ODataAnnotatable ?? property;
-            return HasMaterializedValueCore(annotatableObject);
+            return HasMaterializedValueCore(annotatableObject, materializerContext);
         }
 
         /// <summary>
@@ -41,10 +41,10 @@ public static bool HasMaterializedValue(this ODataProperty property)
         /// </summary>
         /// <param name="property">The property.</param>
         /// <param name="materializedValue">The materialized value.</param>
-        public static void SetMaterializedValue(this ODataProperty property, object materializedValue)
+        public static void SetMaterializedValue(this ODataProperty property, object materializedValue, IODataMaterializerContext materializerContext)
         {
             ODataAnnotatable annotatableObject = property.Value as ODataAnnotatable ?? property;
-            SetMaterializedValueCore(annotatableObject, materializedValue);
+            SetMaterializedValueCore(annotatableObject, materializedValue, materializerContext);
         }
 
         /// <summary>
@@ -52,9 +52,9 @@ public static void SetMaterializedValue(this ODataProperty property, object mate
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
         /// <returns>The materialized value</returns>
-        private static object GetMaterializedValueCore(ODataAnnotatable annotatableObject)
+        private static object GetMaterializedValueCore(ODataAnnotatable annotatableObject, IODataMaterializerContext materializerContext)
         {
-            MaterializerPropertyValue value = annotatableObject.GetAnnotation<MaterializerPropertyValue>();
+            MaterializerPropertyValue value = materializerContext.GetAnnotation<MaterializerPropertyValue>(annotatableObject);
             Debug.Assert(value != null, "MaterializedValue not set");
             return value.Value;
         }
@@ -64,9 +64,9 @@ private static object GetMaterializedValueCore(ODataAnnotatable annotatableObjec
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
         /// <returns><c>true</c> if the value has been materialized; otherwise, <c>false</c>.</returns>
-        private static bool HasMaterializedValueCore(ODataAnnotatable annotatableObject)
+        private static bool HasMaterializedValueCore(ODataAnnotatable annotatableObject, IODataMaterializerContext materializerContext)
         {
-            return annotatableObject.GetAnnotation<MaterializerPropertyValue>() != null;
+            return materializerContext.GetAnnotation<MaterializerPropertyValue>(annotatableObject) != null;
         }
 
         /// <summary>
@@ -74,10 +74,10 @@ private static bool HasMaterializedValueCore(ODataAnnotatable annotatableObject)
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
         /// <param name="materializedValue">The materialized value.</param>
-        private static void SetMaterializedValueCore(ODataAnnotatable annotatableObject, object materializedValue)
+        private static void SetMaterializedValueCore(ODataAnnotatable annotatableObject, object materializedValue, IODataMaterializerContext materializerContext)
         {
             MaterializerPropertyValue materializerValue = new MaterializerPropertyValue { Value = materializedValue };
-            annotatableObject.SetAnnotation(materializerValue);
+            materializerContext.SetAnnotation(annotatableObject, materializerValue);
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
index 950f9c6c23..f065943b06 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
@@ -232,7 +232,7 @@ public static ODataMaterializer CreateMaterializerForMessage(
                     }
 
                     ODataReaderWrapper reader = ODataReaderWrapper.Create(messageReader, payloadKind, edmType, responseInfo.ResponsePipeline);
-                    EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context);
+                    EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, materializerContext);
                     LoadPropertyResponseInfo loadPropertyResponseInfo = responseInfo as LoadPropertyResponseInfo;
 
                     if (loadPropertyResponseInfo != null)
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
index f885159b80..946eb001bd 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
@@ -22,6 +22,7 @@ internal class ODataMaterializerContext : IODataMaterializerContext
         internal ODataMaterializerContext(ResponseInfo responseInfo)
         {
             this.ResponseInfo = responseInfo;
+            this.AnnotationsCache = new MaterializerAnnotationsCache();
         }
 
         /// <summary>
@@ -84,5 +85,7 @@ public IEdmType ResolveExpectedTypeForReading(Type expectedType)
         {
             return this.ResponseInfo.TypeResolver.ResolveExpectedTypeForReading(expectedType);
         }
+
+        public MaterializerAnnotationsCache AnnotationsCache { get; private set; }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
index 6553d4ab6f..f474624db7 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
@@ -44,7 +44,7 @@ public ODataReaderEntityMaterializer(
             : base(materializerContext, entityTrackingAdapter, queryComponents, expectedType, materializeEntryPlan)
         {
             this.messageReader = odataMessageReader;
-            this.feedEntryAdapter = new FeedAndEntryMaterializerAdapter(odataMessageReader, reader, materializerContext.Model, entityTrackingAdapter.MergeOption);
+            this.feedEntryAdapter = new FeedAndEntryMaterializerAdapter(odataMessageReader, reader, materializerContext.Model, entityTrackingAdapter.MergeOption, materializerContext);
         }
 
         /// <summary>
@@ -116,7 +116,7 @@ protected override ODataFormat Format
         /// <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)
+        internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType, IODataMaterializerContext materializerContext)
         {
             ODataPayloadKind messageType = ODataPayloadKind.Resource;
             using (ODataMessageReader messageReader = CreateODataMessageReader(message, responseInfo, ref messageType))
@@ -124,7 +124,7 @@ internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage
                 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);
+                FeedAndEntryMaterializerAdapter parser = new FeedAndEntryMaterializerAdapter(messageReader, reader, responseInfo.Model, responseInfo.MergeOption, materializerContext);
 
                 ODataResource entry = null;
                 bool readFeed = false;
@@ -154,7 +154,7 @@ internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage
                     }
                 }
 
-                return MaterializerEntry.GetEntry(entry);
+                return MaterializerEntry.GetEntry(entry, materializerContext);
             }
         }
 
diff --git a/src/Microsoft.OData.Client/Materialization/StructuralValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/StructuralValueMaterializationPolicy.cs
index c34e4423f4..fe61904f9d 100644
--- a/src/Microsoft.OData.Client/Materialization/StructuralValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/StructuralValueMaterializationPolicy.cs
@@ -114,7 +114,7 @@ internal void MaterializePrimitiveDataValue(Type type, ODataProperty property)
             Debug.Assert(type != null, "type != null");
             Debug.Assert(property != null, "atomProperty != null");
 
-            if (!property.HasMaterializedValue())
+            if (!property.HasMaterializedValue(this.MaterializerContext))
             {
                 object value = property.Value;
                 ODataUntypedValue untypedVal = value as ODataUntypedValue;
@@ -125,7 +125,7 @@ internal void MaterializePrimitiveDataValue(Type type, ODataProperty property)
                 }
 
                 object materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, type);
-                property.SetMaterializedValue(materializedValue);
+                property.SetMaterializedValue(materializedValue, this.MaterializerContext);
             }
         }
 
@@ -218,7 +218,7 @@ internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property,
             else
             {
                 this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property);
-                prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */);
+                prop.SetValue(instance, property.GetMaterializedValue(this.MaterializerContext), property.Name, true /* allowAdd? */);
             }
 
             if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization)
diff --git a/src/Microsoft.OData.Client/MaterializeFromAtom.cs b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
index f2f1525ab0..23621de875 100644
--- a/src/Microsoft.OData.Client/MaterializeFromAtom.cs
+++ b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
@@ -111,7 +111,7 @@ internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> e
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
             QueryComponents qc = new QueryComponents(null, Util.ODataVersionEmpty, elementType, null, null);
             ODataMaterializerContext context = new ODataMaterializerContext(responseInfo);
-            EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context);
+            EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, context);
             this.materializer = new ODataEntriesEntityMaterializer(entries, context, entityTrackingAdapter, qc, materializerType, null, format);
         }
 
diff --git a/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs b/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs
index 7869da711b..eacb02dc99 100644
--- a/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs
+++ b/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs
@@ -11,22 +11,22 @@ namespace Microsoft.OData.Client
 {
     internal static class ODataAnnotatableExtensions
     {
-        public static void SetAnnotation<T>(this ODataAnnotatable annotatable, T annotation)
-            where T : class
-        {
-            Debug.Assert(annotatable != null, "annotatable != null");
-            Debug.Assert(annotation != null, "annotation != null");
-
-            InternalDictionary<T>.SetAnnotation(annotatable, annotation);
-        }
-
-        public static T GetAnnotation<T>(this ODataAnnotatable annotatable)
-            where T : class
-        {
-            Debug.Assert(annotatable != null, "annotatable != null");
-
-            return InternalDictionary<T>.GetAnnotation(annotatable);
-        }
+        //public static void SetAnnotation<T>(this ODataAnnotatable annotatable, T annotation)
+        //    where T : class
+        //{
+        //    Debug.Assert(annotatable != null, "annotatable != null");
+        //    Debug.Assert(annotation != null, "annotation != null");
+
+        //    InternalDictionary<T>.SetAnnotation(annotatable, annotation);
+        //}
+
+        //public static T GetAnnotation<T>(this ODataAnnotatable annotatable)
+        //    where T : class
+        //{
+        //    Debug.Assert(annotatable != null, "annotatable != null");
+
+        //    return InternalDictionary<T>.GetAnnotation(annotatable);
+        //}
 
         private static class InternalDictionary<T> where T : class
         {
diff --git a/src/Microsoft.OData.Client/SaveResult.cs b/src/Microsoft.OData.Client/SaveResult.cs
index 38e1aa6fe2..1e0c20ef9f 100644
--- a/src/Microsoft.OData.Client/SaveResult.cs
+++ b/src/Microsoft.OData.Client/SaveResult.cs
@@ -865,7 +865,8 @@ private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stre
                             responseMsg.StatusCode,
                             () => responseStream);
 
-                        entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType());
+                        ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo);
+                        entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType(), materializerContext);
                         entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor;
                     }
                     catch (Exception ex)

From fa9f65109c13e4b7d25c8f348d5153e52b9ed827 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Mon, 12 Sep 2022 08:32:14 +0300
Subject: [PATCH 02/16] Move up the scope of annotations cache to request-level
 instead of response-level

---
 src/Microsoft.OData.Client/BaseAsyncResult.cs            | 3 +++
 src/Microsoft.OData.Client/BaseSaveResult.cs             | 3 +++
 src/Microsoft.OData.Client/BatchSaveResult.cs            | 6 ++++--
 src/Microsoft.OData.Client/DataServiceRequest.cs         | 7 +++++--
 .../Materialization/ODataMaterializer.cs                 | 5 +++--
 .../Materialization/ODataMaterializerContext.cs          | 4 ++--
 src/Microsoft.OData.Client/MaterializeFromAtom.cs        | 9 +++++----
 src/Microsoft.OData.Client/QueryResult.cs                | 3 ++-
 src/Microsoft.OData.Client/SaveResult.cs                 | 4 ++--
 9 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/src/Microsoft.OData.Client/BaseAsyncResult.cs b/src/Microsoft.OData.Client/BaseAsyncResult.cs
index 7b3d498484..aa31139238 100644
--- a/src/Microsoft.OData.Client/BaseAsyncResult.cs
+++ b/src/Microsoft.OData.Client/BaseAsyncResult.cs
@@ -11,6 +11,7 @@ namespace Microsoft.OData.Client
     using System.IO;
     using System.Threading;
     using Microsoft.OData;
+    using Microsoft.OData.Client.Materialization;
 
     /// <summary>
     /// Implementation of IAsyncResult
@@ -26,6 +27,8 @@ internal abstract class BaseAsyncResult : IAsyncResult
         /// <summary>wrapped request</summary>
         protected PerRequest perRequest;
 
+        protected MaterializerAnnotationsCache annotationsCache = new MaterializerAnnotationsCache();
+
         /// <summary>
         /// The int equivalent for true.
         /// </summary>
diff --git a/src/Microsoft.OData.Client/BaseSaveResult.cs b/src/Microsoft.OData.Client/BaseSaveResult.cs
index 247c8c163b..9f8f46406e 100644
--- a/src/Microsoft.OData.Client/BaseSaveResult.cs
+++ b/src/Microsoft.OData.Client/BaseSaveResult.cs
@@ -19,6 +19,7 @@ namespace Microsoft.OData.Client
     using System.Text;
     using System.Threading;
     using Microsoft.OData;
+    using Microsoft.OData.Client.Materialization;
     using Microsoft.OData.Client.Metadata;
 
     #endregion Namespaces
@@ -66,6 +67,8 @@ internal abstract class BaseSaveResult : BaseAsyncResult
         /// <summary>application/json Content-Type header</summary>
         private const string JsonContentTypeHeader = "application/json";
 
+        protected MaterializerAnnotationsCache annotationsCache = new MaterializerAnnotationsCache();
+
         #endregion Private Fields
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/BatchSaveResult.cs b/src/Microsoft.OData.Client/BatchSaveResult.cs
index f5fe794c94..6327a2b612 100644
--- a/src/Microsoft.OData.Client/BatchSaveResult.cs
+++ b/src/Microsoft.OData.Client/BatchSaveResult.cs
@@ -253,7 +253,8 @@ protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescri
                 queryComponents,
                 /*projectionPlan*/ null,
                 this.currentOperationResponse.CreateResponseMessage(),
-                ODataPayloadKind.Resource);
+                ODataPayloadKind.Resource,
+                this.annotationsCache);
         }
 
         /// <summary>
@@ -688,7 +689,8 @@ private IEnumerable<OperationResponse> HandleBatchResponse(ODataBatchReader batc
                                             null,
                                             this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                             this.currentOperationResponse.CreateResponseMessage(),
-                                            query.PayloadKind);
+                                            query.PayloadKind,
+                                            this.annotationsCache);
                                         qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                     }
                                 }
diff --git a/src/Microsoft.OData.Client/DataServiceRequest.cs b/src/Microsoft.OData.Client/DataServiceRequest.cs
index 6788ebc089..0b6c120703 100644
--- a/src/Microsoft.OData.Client/DataServiceRequest.cs
+++ b/src/Microsoft.OData.Client/DataServiceRequest.cs
@@ -12,6 +12,7 @@ namespace Microsoft.OData.Client
     using System.Linq;
     using System.Net;
     using Microsoft.OData;
+    using Microsoft.OData.Client.Materialization;
 
     /// <summary>Non-generic placeholder for generic implementation</summary>
     public abstract class DataServiceRequest
@@ -66,7 +67,8 @@ internal static MaterializeAtom Materialize(
             ProjectionPlan plan,
             string contentType,
             IODataResponseMessage message,
-            ODataPayloadKind expectedPayloadKind)
+            ODataPayloadKind expectedPayloadKind,
+            MaterializerAnnotationsCache annotationsCache)
         {
             Debug.Assert(queryComponents != null, "querycomponents");
             Debug.Assert(message != null, "message");
@@ -77,7 +79,8 @@ internal static MaterializeAtom Materialize(
                 return MaterializeAtom.EmptyResults;
             }
 
-            return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind);
+            
+            return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind, annotationsCache);
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
index f065943b06..91f2f98d12 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
@@ -191,7 +191,8 @@ public static ODataMaterializer CreateMaterializerForMessage(
             Type materializerType,
             QueryComponents queryComponents,
             ProjectionPlan plan,
-            ODataPayloadKind payloadKind)
+            ODataPayloadKind payloadKind,
+            MaterializerAnnotationsCache annotationsCache)
         {
             ODataMessageReader messageReader = CreateODataMessageReader(responseMessage, responseInfo, ref payloadKind);
 
@@ -200,7 +201,7 @@ public static ODataMaterializer CreateMaterializerForMessage(
 
             try
             {
-                ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo);
+                ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, annotationsCache);
 
                 // Since in V1/V2, astoria client allowed Execute<object> and depended on the typeresolver or the wire type name
                 // to get the clr type to materialize. Hence if we see the materializer type as object, we should set the edmtype
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
index 946eb001bd..923a221257 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
@@ -19,10 +19,10 @@ internal class ODataMaterializerContext : IODataMaterializerContext
         /// Initializes a materializer context
         /// </summary>
         /// <param name="responseInfo">Response information used to initialize with the materializer</param>
-        internal ODataMaterializerContext(ResponseInfo responseInfo)
+        internal ODataMaterializerContext(ResponseInfo responseInfo, MaterializerAnnotationsCache annotationsCache)
         {
             this.ResponseInfo = responseInfo;
-            this.AnnotationsCache = new MaterializerAnnotationsCache();
+            this.AnnotationsCache = annotationsCache;
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/MaterializeFromAtom.cs b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
index 23621de875..401a4e0a5b 100644
--- a/src/Microsoft.OData.Client/MaterializeFromAtom.cs
+++ b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
@@ -79,7 +79,8 @@ internal MaterializeAtom(
             QueryComponents queryComponents,
             ProjectionPlan plan,
             IODataResponseMessage responseMessage,
-            ODataPayloadKind payloadKind)
+            ODataPayloadKind payloadKind,
+            MaterializerAnnotationsCache annotationsCache)
         {
             Debug.Assert(queryComponents != null, "queryComponents != null");
 
@@ -91,7 +92,7 @@ internal MaterializeAtom(
 
             Type implementationType;
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
-            this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind);
+            this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind, annotationsCache);
         }
 
         /// <summary>
@@ -101,7 +102,7 @@ internal MaterializeAtom(
         /// <param name="entries">entries that needs to be materialized.</param>
         /// <param name="elementType">result type.</param>
         /// <param name="format">The format of the response being materialized from.</param>
-        internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> entries, Type elementType, ODataFormat format)
+        internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> entries, Type elementType, ODataFormat format, MaterializerAnnotationsCache annotationsCache)
         {
             this.responseInfo = responseInfo;
             this.elementType = elementType;
@@ -110,7 +111,7 @@ internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> e
             Type implementationType;
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
             QueryComponents qc = new QueryComponents(null, Util.ODataVersionEmpty, elementType, null, null);
-            ODataMaterializerContext context = new ODataMaterializerContext(responseInfo);
+            ODataMaterializerContext context = new ODataMaterializerContext(responseInfo, annotationsCache);
             EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, context);
             this.materializer = new ODataEntriesEntityMaterializer(entries, context, entityTrackingAdapter, qc, materializerType, null, format);
         }
diff --git a/src/Microsoft.OData.Client/QueryResult.cs b/src/Microsoft.OData.Client/QueryResult.cs
index 228ac6d4a5..812da403b0 100644
--- a/src/Microsoft.OData.Client/QueryResult.cs
+++ b/src/Microsoft.OData.Client/QueryResult.cs
@@ -707,7 +707,8 @@ private MaterializeAtom CreateMaterializer(ProjectionPlan plan, ODataPayloadKind
                 plan,
                 this.ContentType,
                 responseMessageWrapper,
-                payloadKind);
+                payloadKind,
+                this.annotationsCache);
         }
     }
 }
diff --git a/src/Microsoft.OData.Client/SaveResult.cs b/src/Microsoft.OData.Client/SaveResult.cs
index 1e0c20ef9f..80ce34218f 100644
--- a/src/Microsoft.OData.Client/SaveResult.cs
+++ b/src/Microsoft.OData.Client/SaveResult.cs
@@ -360,7 +360,7 @@ protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescri
         {
             Debug.Assert(this.cachedResponse.Exception == null && this.cachedResponse.MaterializerEntry != null, "this.cachedResponse.Exception == null && this.cachedResponse.Entry != null");
             ODataResource entry = this.cachedResponse.MaterializerEntry == null ? null : this.cachedResponse.MaterializerEntry.Entry;
-            return new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format);
+            return new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format, annotationsCache);
         }
 
         /// <summary>
@@ -865,7 +865,7 @@ private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stre
                             responseMsg.StatusCode,
                             () => responseStream);
 
-                        ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo);
+                        ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, this.annotationsCache);
                         entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType(), materializerContext);
                         entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor;
                     }

From 17ff489a14a9f919f2dc47cfb11e04ca64c3a36e Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Mon, 12 Sep 2022 10:25:13 +0300
Subject: [PATCH 03/16] Fix e2e tests

---
 .../Tests/DataServiceRequestTests.cs          |  5 ++-
 ...llectionValueMaterializationPolicyTests.cs | 10 ++---
 ...ializationPolicyForComplexResourceTests.cs | 44 ++++++++++---------
 ...ntryValueMaterializationPolicyUnitTests.cs |  5 ++-
 ...eedAndEntryMaterializerAdapterUnitTests.cs |  3 +-
 .../Materialization/MaterializerEntryTests.cs |  4 +-
 .../ODataEntityMaterializerUnitTests.cs       | 11 +++--
 ...ODataEntriesEntityMaterializerUnitTests.cs |  7 +--
 ...rimitiveValueMaterializationPolicyTests.cs |  2 +-
 .../TestMaterializerContext.cs                |  5 ++-
 .../Tests/T4/ODataT4CamelCaseTests.cs         | 25 ++++++-----
 11 files changed, 70 insertions(+), 51 deletions(-)

diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
index 35813b16bb..07fd87e2ee 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
@@ -12,6 +12,7 @@ namespace AstoriaUnitTests.TDD.Tests.Client
     using System.Net;
     using Microsoft.OData;
     using Microsoft.OData.Client;
+    using Microsoft.OData.Client.Materialization;
     using Microsoft.OData.Client.TDDUnitTests;
     using Xunit;
 
@@ -58,13 +59,15 @@ private void MaterializeTest(HttpStatusCode statusCode, ODataPayloadKind payload
                 new HeaderCollection(),
                 (int)statusCode,
                 () => new MemoryStream());
+            var annotationsCache = new MaterializerAnnotationsCache();
             var materialize = DataServiceRequest.Materialize(
                 responseInfo,
                 queryComponents,
                 null,
                 "application/json",
                 responseMessage,
-                payloadKind);
+                payloadKind,
+                annotationsCache);
             Assert.Null(materialize.Context);
             Assert.Null(materialize.Current);
             var enumerable = materialize.Cast<object>();
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
index ec244d9fad..e0e3c7fdb9 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
@@ -130,7 +130,7 @@ public void AddingCollectionToComplexCollectionShouldFail()
         [Fact]
         public void DataServicCollectionOfTAsCollectionTypeShouldFailForPrimitiveOrComplexCollections()
         {
-            var testContext = new TestMaterializerContext();
+            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(MyInfo));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(MyInfo), "MyInfo", testContext.Model);
 
@@ -141,7 +141,7 @@ public void DataServicCollectionOfTAsCollectionTypeShouldFailForPrimitiveOrCompl
         [Fact]
         public void CreateCollectionInstanceShouldFailOnTypeWithNoParametersLessConstructors()
         {
-            var testContext = new TestMaterializerContext();
+            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(ListWithNoEmptyConstructors), "Points", testContext.Model);
 
@@ -153,7 +153,7 @@ public void CreateCollectionInstanceShouldFailOnTypeWithNoParametersLessConstruc
         public void CreateCollectionPropertyInstanceShouldFailOnTypeWithNoParametersLessConstructors()
         {
             var odataProperty = new ODataProperty() { Name = "foo", Value = new ODataCollectionValue() { TypeName = "Points" } };
-            var testContext = new TestMaterializerContext();
+            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             testContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
                 var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
@@ -167,7 +167,7 @@ public void CreateCollectionPropertyInstanceShouldFailOnTypeWithNoParametersLess
         [Fact]
         public void NonMissingMethodExceptionOnCreateInstanceShouldNotBeCaught()
         {
-            var testContext = new TestMaterializerContext();
+            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(ErrorThrowingList), "Points", testContext.Model);
 
@@ -181,7 +181,7 @@ public void NonMissingMethodExceptionOnCreateInstanceShouldNotBeCaught()
 
         internal CollectionValueMaterializationPolicy CreateCollectionValueMaterializationPolicy()
         {
-            return CreateCollectionValueMaterializationPolicy(new TestMaterializerContext());
+            return CreateCollectionValueMaterializationPolicy(new TestMaterializerContext(new MaterializerAnnotationsCache()));
         }
 
         internal CollectionValueMaterializationPolicy CreateCollectionValueMaterializationPolicy(IODataMaterializerContext materializerContext)
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
index 32ca9ea419..8652bd87a5 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
@@ -50,7 +50,7 @@ public void ComplexWithPrimitiveValueShouldMaterialize()
         [Fact]
         public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         {
-            TestMaterializerContext context = new TestMaterializerContext() { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
             CollectionValueMaterializationPolicyTests.Point point = new CollectionValueMaterializationPolicyTests.Point();
             ODataProperty property = new ODataProperty() { Name = "Z", Value = 10 };
             this.CreateEntryMaterializationPolicy(context)
@@ -60,7 +60,7 @@ public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         [Fact]
         public void ApplyNullOnCollectionPropertyShouldError()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = null };
 
@@ -71,7 +71,7 @@ public void ApplyNullOnCollectionPropertyShouldError()
         [Fact]
         public void ApplyStringValueForCollectionPropertyShouldError()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = "foo" };
 
@@ -82,7 +82,8 @@ public void ApplyStringValueForCollectionPropertyShouldError()
         [Fact]
         public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            var annotationsCache = new MaterializerAnnotationsCache();
+            TestMaterializerContext context = new TestMaterializerContext(annotationsCache);
 
             //In a true client, a TypeResolver will be used to resolve derived property type.
             context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
@@ -98,7 +99,7 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
             };
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
-            var materializerEntry = MaterializerEntry.CreateEntry(derivedResource, ODataFormat.Json, true, clientEdmModel);
+            var materializerEntry = MaterializerEntry.CreateEntry(derivedResource, ODataFormat.Json, true, clientEdmModel, context);
             this.CreateEntryMaterializationPolicy(context).Materialize(materializerEntry, typeof(ChildComplexType), false);
 
             var derived = materializerEntry.ResolvedObject as DerivedComplexType;
@@ -109,7 +110,7 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyDerivedComplexForBaseComplexTypeProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
 
             context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
@@ -140,7 +141,7 @@ public void ApplyDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
 
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings.Add("ShouldBeCleared");
@@ -156,7 +157,7 @@ public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         [Fact]
         public void ApplyODataCollectionValueToNullCollectionProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings = null;
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = new ODataCollectionValue() { Items = new string[] { "foo" }, TypeName = typeof(ComplexTypeWithPrimitiveCollection).FullName } };
@@ -171,7 +172,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         {
             foreach (var startingPropertyState in new ChildComplexType[] { null, new ChildComplexType() })
             {
-                TestMaterializerContext context = new TestMaterializerContext();
+                TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
                 ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
                 complexInstance.InnerComplexProperty = startingPropertyState;
                 var innerEntry = new ODataResource() { Properties = new ODataProperty[] { new ODataProperty() { Name = "Prop", Value = 1 } } };
@@ -183,7 +184,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         [Fact]
         public void NullValueShouldBeAppliedToSubComplexValueProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext();
+            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
             complexInstance.InnerComplexProperty = new ChildComplexType();
 
@@ -193,25 +194,25 @@ public void NullValueShouldBeAppliedToSubComplexValueProperty()
 
         private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext context = null)
         {
-            context = context ?? new TestMaterializerContext();
+            context = context ?? new TestMaterializerContext(new MaterializerAnnotationsCache());
             var resource = new ODataResource() { TypeName = "ComplexTypeWithChildComplexType", Properties = new ODataProperty[0] };
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
-            var materializerEntry = MaterializerEntry.CreateEntry(resource, ODataFormat.Json, false, clientEdmModel);
+            var materializerEntry = MaterializerEntry.CreateEntry(resource, ODataFormat.Json, false, clientEdmModel, context);
             materializerEntry.ResolvedObject = parentInstance;
             ODataNestedResourceInfo innerComplexP = new ODataNestedResourceInfo() { Name = "InnerComplexProperty", IsCollection = false };
 
             MaterializerEntry innerMaterializerEntry;
             if (innerResource != null)
             {
-                innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel);
+                innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel, context);
             }
             else
             {
                 innerMaterializerEntry = MaterializerEntry.CreateEmpty();
             }
 
-            MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry);
+            MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry, context);
             materializerEntry.AddNestedResourceInfo(innerComplexP);
 
             var policy = this.CreateEntryMaterializationPolicy(context);
@@ -223,8 +224,8 @@ internal EntryValueMaterializationPolicy CreateEntryMaterializationPolicy(TestMa
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            materializerContext = materializerContext ?? new TestMaterializerContext() { Model = clientEdmModel, Context = context };
-            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             var lazyPrimitivePropertyConverter = new DSClient.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter());
             var primitiveValueMaterializerPolicy = new PrimitiveValueMaterializationPolicy(materializerContext, lazyPrimitivePropertyConverter);
             var entryPolicy = new EntryValueMaterializationPolicy(materializerContext, adapter, lazyPrimitivePropertyConverter, null);
@@ -273,7 +274,7 @@ public void ShouldMaterializeConcreteComplexCollectionDeclaredAsAbstract()
                 new ODataResource(){Properties = new ODataProperty[]{ new ODataProperty(){Name="Points", Value = 0}, new ODataProperty(){Name="Diameter", Value = 18} }},
             });
 
-            var testContext = new TestMaterializerContext();
+            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             testContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
                 var edmType = testContext.Model.GetOrCreateEdmType(typeof(CollectionValueMaterializationPolicyTests.Circle));
@@ -327,9 +328,10 @@ internal ODataEntriesEntityMaterializer CreateODataEntriesEntityMaterializer(
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
 
             var resourceSet = new ODataResourceSet();
-            MaterializerFeed.CreateFeed(resourceSet, resources);
+            MaterializerFeed.CreateFeed(resourceSet, resources, materializerContext);
             resources.ForEach(r =>
             {
                 if (r == null)
@@ -338,11 +340,11 @@ internal ODataEntriesEntityMaterializer CreateODataEntriesEntityMaterializer(
                 }
                 else
                 {
-                    MaterializerEntry.CreateEntry(r, ODataFormat.Json, true, clientEdmModel);
+                    MaterializerEntry.CreateEntry(r, ODataFormat.Json, true, clientEdmModel, materializerContext);
                 }
             });
-            materializerContext = materializerContext ?? new TestMaterializerContext() { Model = clientEdmModel, Context = context };
-            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
+            
+            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             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);
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
index b11e9304b5..fa5ae38c07 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
@@ -41,7 +41,7 @@ public EntryValueMaterializationPolicyUnitTests()
             this.clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             this.clientEdmModel.GetOrCreateEdmType(typeof(TestCustomer));
             this.clientEdmModel.GetOrCreateEdmType(typeof(TestOrder));
-            this.materializerContext = new TestMaterializerContext() { Model = this.clientEdmModel };
+            this.materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = this.clientEdmModel };
             this.ordersProperty = this.clientEdmModel.GetClientTypeAnnotation(typeof(TestCustomer)).GetProperty("Orders", UndeclaredPropertyBehavior.ThrowException);
         }
 
@@ -293,7 +293,8 @@ private void TestApplyItemsToCollection(
                 entityTracker,
                 option,
                 clientEdmModel,
-                new DataServiceContext());
+                new DataServiceContext(),
+                materializerContext);
 
             EntryValueMaterializationPolicy evmp = new EntryValueMaterializationPolicy(
                 materializerContext,
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
index 9307c70f12..09a01fa39a 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
@@ -52,7 +52,8 @@ public void ValidateShortIntegrationFeedReading()
 
             var responsePipeline = new DataServiceClientResponsePipelineConfiguration(new DataServiceContext());
             var odataReaderWrapper = ODataReaderWrapper.CreateForTest(testODataReader, responsePipeline);
-            FeedAndEntryMaterializerAdapter reader = new FeedAndEntryMaterializerAdapter(ODataFormat.Json, odataReaderWrapper, clientEdmModel, MergeOption.OverwriteChanges);
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            FeedAndEntryMaterializerAdapter reader = new FeedAndEntryMaterializerAdapter(ODataFormat.Json, odataReaderWrapper, clientEdmModel, MergeOption.OverwriteChanges, materializerContext);
 
             int readCounter = 0;
 
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
index 722d589684..8a455e455b 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
@@ -13,6 +13,7 @@ namespace AstoriaUnitTests.TDD.Tests.Client.Materialization
     using Microsoft.OData;
     using ClientStrings = Microsoft.OData.Client.Strings;
     using Xunit;
+    using AstoriaUnitTests.Tests;
 
     /// <summary>
     /// TODO: test the rest of the functionality in <see cref="MaterializerEntry"/>.
@@ -63,7 +64,8 @@ private MaterializerEntry CreateMaterializerEntry(ODataFormat format, Action<ODa
                 modifyEntry(entry);
             }
 
-            return MaterializerEntry.CreateEntry(entry, format, true, this.clientModel);
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            return MaterializerEntry.CreateEntry(entry, format, true, this.clientModel, materializerContext);
         }
     }
 }
\ No newline at end of file
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
index 65d05c0dcb..23d771e718 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
@@ -12,6 +12,7 @@ namespace AstoriaUnitTests.TDD.Tests.Client
     using FluentAssertions;
     using Microsoft.OData;
     using Xunit;
+    using AstoriaUnitTests.Tests;
 
     /// <summary>
     /// Unit tests for the ODataEntityMaterializerUnitTests class.
@@ -30,27 +31,29 @@ public ODataEntityMaterializerUnitTests()
         [Fact]
         public void AfterEntryMaterializedShouldOccur()
         {
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+
             foreach (ODataFormat format in new ODataFormat[] { ODataFormat.Json })
             {
                 var entity = new SimpleEntity() { ID = 1 };
-                var odataEntry = CreateEntryWithMaterializerEntry(format, entity);
+                var odataEntry = CreateEntryWithMaterializerEntry(format, entity, materializerContext);
                 MaterializedEntityArgs found = null;
                 this.context.Configurations.ResponsePipeline.OnEntityMaterialized((MaterializedEntityArgs materializedEntryEventArgs) => found = materializedEntryEventArgs);
 
-                this.context.Configurations.ResponsePipeline.FireEndEntryEvents(MaterializerEntry.GetEntry(odataEntry));
+                this.context.Configurations.ResponsePipeline.FireEndEntryEvents(MaterializerEntry.GetEntry(odataEntry, materializerContext));
                 Assert.NotNull(found);
                 found.Entity.Should().Be(entity);
                 found.Entry.Should().Be(odataEntry);
             }
         }
 
-        private ODataResource CreateEntryWithMaterializerEntry(ODataFormat format, object resolvedObject)
+        private ODataResource CreateEntryWithMaterializerEntry(ODataFormat format, object resolvedObject, IODataMaterializerContext materializerContext)
         {
             var entry = new ODataResource();
             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);
+            var materializerEntry = MaterializerEntry.CreateEntry(entry, format, true, this.clientModel, materializerContext);
             materializerEntry.ResolvedObject = resolvedObject;
 
             return entry;
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
index 28ca7c8f93..0b7550541b 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
@@ -30,9 +30,10 @@ public void ShortIntegrationTestToValidateEntryShouldBeRead()
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            MaterializerEntry.CreateEntry(odataEntry, ODataFormat.Json, true, clientEdmModel);
-            var materializerContext = new TestMaterializerContext() { Model = clientEdmModel, Context = context };
-            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            MaterializerEntry.CreateEntry(odataEntry, ODataFormat.Json, true, clientEdmModel, materializerContext);
+            
+            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             QueryComponents components = new QueryComponents(new Uri("http://foo.com/Service"), new Version(4, 0), typeof(Customer), null, new Dictionary<Expression, Expression>());
 
             var entriesMaterializer = new ODataEntriesEntityMaterializer(new ODataResource[] { odataEntry }, materializerContext, adapter, components, typeof(Customer), null, ODataFormat.Json);
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
index 56716e1a4b..2da7be54a6 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
@@ -63,7 +63,7 @@ public void TimeOfDayValueShouldMaterializeCorrectly()
 
         internal PrimitiveValueMaterializationPolicy CreatePrimitiveValueMaterializationPolicy()
         {
-            return new PrimitiveValueMaterializationPolicy(new TestMaterializerContext(), new SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter()));
+            return new PrimitiveValueMaterializationPolicy(new TestMaterializerContext(new MaterializerAnnotationsCache()), new SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter()));
         }
 
         public class UnknownPoint
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
index 93e270bd5e..67bbf93737 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
@@ -17,12 +17,13 @@ namespace AstoriaUnitTests.Tests
     /// </summary>
     internal class TestMaterializerContext : IODataMaterializerContext
     {
-        public TestMaterializerContext()
+        public TestMaterializerContext(MaterializerAnnotationsCache annotationsCache)
         {
             this.UndeclaredPropertyBehavior = UndeclaredPropertyBehavior.ThrowException;
             this.ResponsePipeline = new DataServiceClientResponsePipelineConfiguration(this);
             this.Model = new ClientEdmModel(ODataProtocolVersion.V4);
             this.Context = new DataServiceContext();
+            this.AnnotationsCache = annotationsCache;
         }
 
         public Func<Type, string, ClientTypeAnnotation> ResolveTypeForMaterializationOverrideFunc { get; set; }
@@ -50,5 +51,7 @@ public IEdmType ResolveExpectedTypeForReading(Type expectedType)
         }
 
         public DataServiceContext Context { get; set; }
+
+        public MaterializerAnnotationsCache AnnotationsCache { get; private set; }
     }
 }
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
index 35a0e8edc3..3a7546d2d9 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
@@ -322,14 +322,14 @@ public void MaterializeEntityShouldWork()
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            var materializerEntry = MaterializerEntry.CreateEntry(odataEntry, OData.ODataFormat.Json, true, clientEdmModel);
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            var materializerEntry = MaterializerEntry.CreateEntry(odataEntry, OData.ODataFormat.Json, true, clientEdmModel, materializerContext);
 
-            MaterializerNavigationLink.CreateLink(complexP, MaterializerEntry.CreateEntry(complexResource, OData.ODataFormat.Json, true, clientEdmModel));
-            MaterializerFeed.CreateFeed(complexColResourceSet, items);
-            MaterializerNavigationLink.CreateLink(complexColP, complexColResourceSet);
+            MaterializerNavigationLink.CreateLink(complexP, MaterializerEntry.CreateEntry(complexResource, OData.ODataFormat.Json, true, clientEdmModel, materializerContext), materializerContext);
+            MaterializerFeed.CreateFeed(complexColResourceSet, items, materializerContext);
+            MaterializerNavigationLink.CreateLink(complexColP, complexColResourceSet, materializerContext);
 
-            var materializerContext = new TestMaterializerContext() { Model = clientEdmModel, Context = context };
-            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
+            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             QueryComponents components = new QueryComponents(new Uri("http://foo.com/Service"), new Version(4, 0), typeof(EntityType), null, new Dictionary<Expression, Expression>());
 
             var entriesMaterializer = new ODataEntriesEntityMaterializer(new OData.ODataResource[] { odataEntry }, materializerContext, adapter, components, typeof(EntityType), null, OData.ODataFormat.Json);
@@ -381,7 +381,9 @@ public void MaterializeComplexTypeShouldWork()
                     }
                 }
             };
-            var materializerEntry = MaterializerEntry.CreateEntry(complexValue, OData.ODataFormat.Json, false, new ClientEdmModel(ODataProtocolVersion.V4));
+
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerEntry = MaterializerEntry.CreateEntry(complexValue, OData.ODataFormat.Json, false, new ClientEdmModel(ODataProtocolVersion.V4), materializerContext);
             this.CreateEntryMaterializationPolicy().Materialize(materializerEntry, typeof(ComplexType), false);
             var complex = materializerEntry.ResolvedObject as ComplexType;
             complex.Name.Should().Be("June");
@@ -396,9 +398,10 @@ public void MaterializeEnumTypeShouldWork()
         {
             OData.ODataEnumValue enumValue = new OData.ODataEnumValue("blue");
             OData.ODataProperty property = new OData.ODataProperty { Name = "enumProperty", Value = enumValue };
-            var enumPolicy = new EnumValueMaterializationPolicy(new TestMaterializerContext());
+            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var enumPolicy = new EnumValueMaterializationPolicy(materializerContext);
             var result = enumPolicy.MaterializeEnumTypeProperty(typeof(Color), property);
-            property.GetMaterializedValue().Should().Be(Color.Blue);
+            property.GetMaterializedValue(materializerContext).Should().Be(Color.Blue);
             result.Should().Be(Color.Blue);
         }
 
@@ -470,8 +473,8 @@ internal EntryValueMaterializationPolicy CreateEntryMaterializationPolicy(TestMa
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext().ReConfigureForNetworkLoadingTests();
-            materializerContext = materializerContext ?? new TestMaterializerContext() { Model = clientEdmModel, Context = context };
-            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context);
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             var lazyPrimitivePropertyConverter = new Microsoft.OData.Client.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter());
             var primitiveValueMaterializerPolicy = new PrimitiveValueMaterializationPolicy(materializerContext, lazyPrimitivePropertyConverter);
             var entryPolicy = new EntryValueMaterializationPolicy(materializerContext, adapter, lazyPrimitivePropertyConverter, null);

From b542679b32c20eace385e2d151584f1d0b353b8e Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Mon, 12 Sep 2022 11:34:33 +0300
Subject: [PATCH 04/16] Pass materializerContext argument to dynamically-called
 methods

---
 .../Materialization/ODataEntityMaterializer.cs       |  6 +++---
 src/Microsoft.OData.Client/ProjectionPlanCompiler.cs | 12 ++++++++----
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
index 384a0a5a4f..318bcddde1 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
@@ -49,7 +49,7 @@ public ODataEntityMaterializer(
             ProjectionPlan materializeEntryPlan)
             : base(materializerContext, expectedType)
         {
-            this.materializeEntryPlan = materializeEntryPlan ?? CreatePlan(queryComponents);
+            this.materializeEntryPlan = materializeEntryPlan ?? CreatePlan(queryComponents, materializerContext);
             this.EntityTrackingAdapter = entityTrackingAdapter;
             DSClient.SimpleLazy<PrimitivePropertyConverter> converter = new DSClient.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter());
 
@@ -959,7 +959,7 @@ private static void CheckEntryToAccessNotNull(MaterializerEntry entry, string na
         /// <summary>Creates an entry materialization plan for a given projection.</summary>
         /// <param name="queryComponents">Query components for plan to materialize.</param>
         /// <returns>A materialization plan.</returns>
-        private static ProjectionPlan CreatePlan(QueryComponents queryComponents)
+        private static ProjectionPlan CreatePlan(QueryComponents queryComponents, IODataMaterializerContext materializerContext)
         {
             // Can we have a primitive property as well?
             LambdaExpression projection = queryComponents.Projection;
@@ -977,7 +977,7 @@ private static ProjectionPlan CreatePlan(QueryComponents queryComponents)
                 }
                 else
                 {
-                    result = ProjectionPlanCompiler.CompilePlan(projection, queryComponents.NormalizerRewrites);
+                    result = ProjectionPlanCompiler.CompilePlan(projection, queryComponents.NormalizerRewrites, materializerContext);
                 }
 
                 result.LastSegmentType = queryComponents.LastSegmentType;
diff --git a/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs b/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
index 4f571ae7da..7f46be6a2e 100644
--- a/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
+++ b/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
@@ -51,6 +51,8 @@ internal class ProjectionPlanCompiler : ALinqExpressionVisitor
         /// <summary>Whether the top level projection has been found.</summary>
         private bool topLevelProjectionFound;
 
+        IODataMaterializerContext materializerContext;
+
         #endregion Private fields
 
         #region Constructors
@@ -59,12 +61,13 @@ internal class ProjectionPlanCompiler : ALinqExpressionVisitor
         /// Initializes a new <see cref="ProjectionPlanCompiler"/> instance.
         /// </summary>
         /// <param name="normalizerRewrites">Rewrites introduces by normalizer.</param>
-        private ProjectionPlanCompiler(Dictionary<Expression, Expression> normalizerRewrites)
+        private ProjectionPlanCompiler(Dictionary<Expression, Expression> normalizerRewrites, IODataMaterializerContext materializerContext)
         {
             this.annotations = new Dictionary<Expression, ExpressionAnnotation>(ReferenceEqualityComparer<Expression>.Instance);
             this.materializerExpression = Expression.Parameter(typeof(object), "mat");
             this.normalizerRewrites = normalizerRewrites;
             this.pathBuilder = new ProjectionPathBuilder();
+            this.materializerContext = materializerContext;
         }
 
         #endregion Constructors
@@ -75,7 +78,7 @@ private ProjectionPlanCompiler(Dictionary<Expression, Expression> normalizerRewr
         /// <param name="projection">Projection expression.</param>
         /// <param name="normalizerRewrites">Tracks rewrite-to-source rewrites introduced by expression normalizer.</param>
         /// <returns>A new <see cref="ProjectionPlan"/> instance.</returns>
-        internal static ProjectionPlan CompilePlan(LambdaExpression projection, Dictionary<Expression, Expression> normalizerRewrites)
+        internal static ProjectionPlan CompilePlan(LambdaExpression projection, Dictionary<Expression, Expression> normalizerRewrites, IODataMaterializerContext materializerContext)
         {
             Debug.Assert(projection != null, "projection != null");
             Debug.Assert(projection.Parameters.Count == 1, "projection.Parameters.Count == 1");
@@ -88,7 +91,7 @@ internal static ProjectionPlan CompilePlan(LambdaExpression projection, Dictiona
                 projection.Body.NodeType == ExpressionType.New,
                 "projection.Body.NodeType == Constant, MemberInit, MemberAccess, Convert(Checked) New");
 
-            ProjectionPlanCompiler rewriter = new ProjectionPlanCompiler(normalizerRewrites);
+            ProjectionPlanCompiler rewriter = new ProjectionPlanCompiler(normalizerRewrites, materializerContext);
 #if TRACE_CLIENT_PROJECTIONS
             Trace.WriteLine("Projection: " + projection);
 #endif
@@ -666,7 +669,8 @@ private Expression RebindEntityMemberInit(MemberInitExpression init)
                     Expression nestedEntry = CallMaterializer(
                         "ProjectionGetEntry",
                         entryParameterAtMemberInit,
-                        Expression.Constant(assignment.Member.Name, typeof(string)));
+                        Expression.Constant(assignment.Member.Name, typeof(string)),
+                        Expression.Constant(this.materializerContext));
                     ParameterExpression nestedEntryParameter = Expression.Parameter(
                         typeof(object),
                         "subentry" + (this.identifierId++).ToString(CultureInfo.InvariantCulture));

From eabc99ba920092b6e53a8fb3a197c76a4a181fb2 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Thu, 15 Sep 2022 06:58:22 +0300
Subject: [PATCH 05/16] Make MaterializerAnnotatonsCache sealed

---
 .../Materialization/MaterializerAnnotationsCache.cs      | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
index 1c14b2e349..b81ac617c5 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -1,14 +1,9 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace Microsoft.OData.Client.Materialization
 {
-    internal class MaterializerAnnotationsCache
+    internal sealed class MaterializerAnnotationsCache
     {
         private readonly Dictionary<ODataAnnotatable, object> cache = new Dictionary<ODataAnnotatable, object>(ReferenceEqualityComparer<ODataAnnotatable>.Instance);
 

From b2bf1ee351579c22726af1b0f5f38968bddd9634 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Thu, 15 Sep 2022 07:27:40 +0300
Subject: [PATCH 06/16] Add doc comments to MaterializerAnnotationsCache

---
 .../MaterializerAnnotationsCache.cs           | 53 ++++++++++++++++++-
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
index b81ac617c5..98490e4b7d 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -3,21 +3,55 @@
 
 namespace Microsoft.OData.Client.Materialization
 {
+    /// <summary>
+    /// A cache used to store temporary materialization metadata
+    /// for deseriliazed <see cref="ODataItem"/>s during materialization of response payloads
+    /// into client CLR objects. Keys are identified using reference equality.
+    /// </summary>
+    /// <remarks>
+    /// Instances of the cache are not thread-safe. Each instance is expected to be used within the
+    /// scope of a single request.
+    /// 
+    /// The cache is designed to store one entry type per key. For example, if the key is
+    /// an <see cref="ODataResource"/>, its value should be a <see cref="MaterializerEntry"/>. It also
+    /// expects the value for any given key will not change.
+    /// So you should call `cache.SetAnnotation(odataResource, materializerEntry)` add the cache entry
+    /// and `cache.GetAnnotations<MaterializerEntry>(odataResource)` to retrieve the entry.
+    /// 
+    /// If the requirements change such that we need to allow updating the value of a key to a different type,
+    /// then the cache should be redesigned.
+    /// </remarks>
     internal sealed class MaterializerAnnotationsCache
     {
         private readonly Dictionary<ODataAnnotatable, object> cache = new Dictionary<ODataAnnotatable, object>(ReferenceEqualityComparer<ODataAnnotatable>.Instance);
 
+        /// <summary>
+        /// Adds an entry to the cache with the <paramref name="annotatable"/>
+        /// set as key,
+        /// </summary>
+        /// <typeparam name="T">The type of the value.</typeparam>
+        /// <param name="annotatable">The key of the entry.</param>
+        /// <param name="value">The value to associate with the key.</param>
         public void SetAnnotation<T>(ODataAnnotatable annotatable, T value) where T : class
         {
+            Debug.Assert(annotatable != null, "annotatable != null");
             this.cache.Add(annotatable, value);
         }
 
+        /// <summary>
+        /// Retrieves the value associated with the specified <paramref name="annotatable"/>.
+        /// Returns null if the cache does not contain an entry with the specifiedy key.
+        /// </summary>
+        /// <typeparam name="T">The expected type of the value.</typeparam>
+        /// <param name="annotatable"></param>
+        /// <returns>The value associated with the specified <paramref name="annotatable"/> if the entry exists, or null otherwise.</returns>
         public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
         {
             if (this.cache.TryGetValue(annotatable, out object value))
             {
-                Debug.Assert(value is T);
-                return value as T;
+                T valueAsT = value as T;
+                Debug.Assert(valueAsT != null, "valueAsT != null");
+                return valueAsT;
             }
 
             return default(T);
@@ -26,11 +60,26 @@ public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
 
     internal static class MaterializerContextExtensions
     {
+        /// <summary>
+        /// Associates the specified annotation <paramref name="value"/> with the specified
+        /// <paramref name="annotatable"/> to store metadata used for materialization.
+        /// </summary>
+        /// <typeparam name="T">The type of the value.</typeparam>
+        /// <param name="context">The materializer context.</param>
+        /// <param name="annotatable">The item to annotate.</param>
+        /// <param name="value">The annotation value.</param>
         public static void SetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable, T value) where T : class
         {
             context.AnnotationsCache.SetAnnotation(annotatable, value);
         }
 
+        /// <summary>
+        /// Retrieves the annotation value associated with te specified <paramref name="annotatable"/>.
+        /// </summary>
+        /// <typeparam name="T">The expected type of the annotation value.</typeparam>
+        /// <param name="context">The materializer context.</param>
+        /// <param name="annotatable">The item for which to retrieve the annotation.</param>
+        /// <returns>The annotation value associated with the <paramref name="annotatable"/> if it exists, or null otherwise.</returns>
         public static T GetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable) where T : class
         {
             return context.AnnotationsCache.GetAnnotation<T>(annotatable);

From 53803d9c8ef0611e522ffc9f40822f36396743f4 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Thu, 15 Sep 2022 07:32:37 +0300
Subject: [PATCH 07/16] Remove ODataAnnotatableExtensions

---
 .../MaterializerAnnotationsCache.cs           | 36 +++----------
 .../MaterializerContextExtensions.cs          | 36 +++++++++++++
 .../ODataAnnotatableExtensions.cs             | 53 -------------------
 3 files changed, 43 insertions(+), 82 deletions(-)
 create mode 100644 src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
 delete mode 100644 src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs

diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
index 98490e4b7d..5f8599f6b2 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -1,4 +1,10 @@
-using System.Collections.Generic;
+//---------------------------------------------------------------------
+// <copyright file="MaterializerAnnotationsCache.cs" company="Microsoft">
+//      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+// </copyright>
+//---------------------------------------------------------------------
+
+using System.Collections.Generic;
 using System.Diagnostics;
 
 namespace Microsoft.OData.Client.Materialization
@@ -57,32 +63,4 @@ public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
             return default(T);
         }
     }
-
-    internal static class MaterializerContextExtensions
-    {
-        /// <summary>
-        /// Associates the specified annotation <paramref name="value"/> with the specified
-        /// <paramref name="annotatable"/> to store metadata used for materialization.
-        /// </summary>
-        /// <typeparam name="T">The type of the value.</typeparam>
-        /// <param name="context">The materializer context.</param>
-        /// <param name="annotatable">The item to annotate.</param>
-        /// <param name="value">The annotation value.</param>
-        public static void SetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable, T value) where T : class
-        {
-            context.AnnotationsCache.SetAnnotation(annotatable, value);
-        }
-
-        /// <summary>
-        /// Retrieves the annotation value associated with te specified <paramref name="annotatable"/>.
-        /// </summary>
-        /// <typeparam name="T">The expected type of the annotation value.</typeparam>
-        /// <param name="context">The materializer context.</param>
-        /// <param name="annotatable">The item for which to retrieve the annotation.</param>
-        /// <returns>The annotation value associated with the <paramref name="annotatable"/> if it exists, or null otherwise.</returns>
-        public static T GetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable) where T : class
-        {
-            return context.AnnotationsCache.GetAnnotation<T>(annotatable);
-        }
-    }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
new file mode 100644
index 0000000000..1a2c7b72c2
--- /dev/null
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
@@ -0,0 +1,36 @@
+//---------------------------------------------------------------------
+// <copyright file="MaterializerContextExtensions.cs" company="Microsoft">
+//      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+// </copyright>
+//---------------------------------------------------------------------
+
+namespace Microsoft.OData.Client.Materialization
+{
+    internal static class MaterializerContextExtensions
+    {
+        /// <summary>
+        /// Associates the specified annotation <paramref name="value"/> with the specified
+        /// <paramref name="annotatable"/> to store metadata used for materialization.
+        /// </summary>
+        /// <typeparam name="T">The type of the value.</typeparam>
+        /// <param name="context">The materializer context.</param>
+        /// <param name="annotatable">The item to annotate.</param>
+        /// <param name="value">The annotation value.</param>
+        public static void SetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable, T value) where T : class
+        {
+            context.AnnotationsCache.SetAnnotation(annotatable, value);
+        }
+
+        /// <summary>
+        /// Retrieves the annotation value associated with te specified <paramref name="annotatable"/>.
+        /// </summary>
+        /// <typeparam name="T">The expected type of the annotation value.</typeparam>
+        /// <param name="context">The materializer context.</param>
+        /// <param name="annotatable">The item for which to retrieve the annotation.</param>
+        /// <returns>The annotation value associated with the <paramref name="annotatable"/> if it exists, or null otherwise.</returns>
+        public static T GetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable) where T : class
+        {
+            return context.AnnotationsCache.GetAnnotation<T>(annotatable);
+        }
+    }
+}
diff --git a/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs b/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs
deleted file mode 100644
index eacb02dc99..0000000000
--- a/src/Microsoft.OData.Client/ODataAnnotatableExtensions.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-//---------------------------------------------------------------------
-// <copyright file="ODataAnnotatableExtensions.cs" company="Microsoft">
-//      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
-// </copyright>
-//---------------------------------------------------------------------
-
-using System.Runtime.CompilerServices;
-using System.Diagnostics;
-
-namespace Microsoft.OData.Client
-{
-    internal static class ODataAnnotatableExtensions
-    {
-        //public static void SetAnnotation<T>(this ODataAnnotatable annotatable, T annotation)
-        //    where T : class
-        //{
-        //    Debug.Assert(annotatable != null, "annotatable != null");
-        //    Debug.Assert(annotation != null, "annotation != null");
-
-        //    InternalDictionary<T>.SetAnnotation(annotatable, annotation);
-        //}
-
-        //public static T GetAnnotation<T>(this ODataAnnotatable annotatable)
-        //    where T : class
-        //{
-        //    Debug.Assert(annotatable != null, "annotatable != null");
-
-        //    return InternalDictionary<T>.GetAnnotation(annotatable);
-        //}
-
-        private static class InternalDictionary<T> where T : class
-        {
-            private static readonly ConditionalWeakTable<ODataAnnotatable, T> Dictionary =
-                new ConditionalWeakTable<ODataAnnotatable, T>();
-
-            public static void SetAnnotation(ODataAnnotatable annotatable, T annotation)
-            {
-                Dictionary.Add(annotatable, annotation);
-            }
-
-            public static T GetAnnotation(ODataAnnotatable annotatable)
-            {
-                T annotation;
-                if (Dictionary.TryGetValue(annotatable, out annotation))
-                {
-                    return annotation;
-                }
-
-                return default(T);
-            }
-        }
-    }
-}

From 5a66220ec6e836271301854045bbf3d83f1c3187 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Thu, 15 Sep 2022 08:40:22 +0300
Subject: [PATCH 08/16] Update doc comments

---
 src/Microsoft.OData.Client/AtomMaterializerLog.cs      |  4 ++++
 src/Microsoft.OData.Client/BaseAsyncResult.cs          |  3 +++
 src/Microsoft.OData.Client/BaseSaveResult.cs           |  2 --
 src/Microsoft.OData.Client/DataServiceRequest.cs       |  1 +
 .../Materialization/EntityTrackingAdapter.cs           |  1 +
 .../Materialization/FeedAndEntryMaterializerAdapter.cs |  7 ++++++-
 .../Materialization/MaterializerEntry.cs               |  2 ++
 .../Materialization/MaterializerFeed.cs                |  2 ++
 .../Materialization/MaterializerNavigationLink.cs      |  9 +++++++--
 .../Materialization/ODataEntityMaterializer.cs         |  2 ++
 .../Materialization/ODataEntityMaterializerInvoker.cs  |  2 ++
 .../Materialization/ODataItemExtensions.cs             | 10 ++++++++--
 .../Materialization/ODataReaderEntityMaterializer.cs   |  1 +
 src/Microsoft.OData.Client/MaterializeFromAtom.cs      |  2 ++
 src/Microsoft.OData.Client/ProjectionPlanCompiler.cs   |  6 +++++-
 15 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/src/Microsoft.OData.Client/AtomMaterializerLog.cs b/src/Microsoft.OData.Client/AtomMaterializerLog.cs
index 0b79b25428..5f39833c57 100644
--- a/src/Microsoft.OData.Client/AtomMaterializerLog.cs
+++ b/src/Microsoft.OData.Client/AtomMaterializerLog.cs
@@ -46,6 +46,9 @@ internal class AtomMaterializerLog
         /// <summary>Target instance to refresh.</summary>
         private object insertRefreshObject;
 
+        /// <summary>
+        /// The materializer context.
+        /// </summary>
         private IODataMaterializerContext materializerContext;
 
         #endregion Private fields
@@ -58,6 +61,7 @@ internal class AtomMaterializerLog
         /// <param name="mergeOption">The merge option for the log.</param>
         /// <param name="model">The model for the log.</param>
         /// <param name="entityTracker">The entity tracker for the log.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <remarks>
         /// Note that the merge option can't be changed.
         /// </remarks>
diff --git a/src/Microsoft.OData.Client/BaseAsyncResult.cs b/src/Microsoft.OData.Client/BaseAsyncResult.cs
index aa31139238..323c792089 100644
--- a/src/Microsoft.OData.Client/BaseAsyncResult.cs
+++ b/src/Microsoft.OData.Client/BaseAsyncResult.cs
@@ -27,6 +27,9 @@ internal abstract class BaseAsyncResult : IAsyncResult
         /// <summary>wrapped request</summary>
         protected PerRequest perRequest;
 
+        /// <summary>
+        /// Cache used to store temporary metadata for OData items during materialization.
+        /// </summary>
         protected MaterializerAnnotationsCache annotationsCache = new MaterializerAnnotationsCache();
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/BaseSaveResult.cs b/src/Microsoft.OData.Client/BaseSaveResult.cs
index 9f8f46406e..5f44c01272 100644
--- a/src/Microsoft.OData.Client/BaseSaveResult.cs
+++ b/src/Microsoft.OData.Client/BaseSaveResult.cs
@@ -67,8 +67,6 @@ internal abstract class BaseSaveResult : BaseAsyncResult
         /// <summary>application/json Content-Type header</summary>
         private const string JsonContentTypeHeader = "application/json";
 
-        protected MaterializerAnnotationsCache annotationsCache = new MaterializerAnnotationsCache();
-
         #endregion Private Fields
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/DataServiceRequest.cs b/src/Microsoft.OData.Client/DataServiceRequest.cs
index 0b6c120703..273202ee4f 100644
--- a/src/Microsoft.OData.Client/DataServiceRequest.cs
+++ b/src/Microsoft.OData.Client/DataServiceRequest.cs
@@ -60,6 +60,7 @@ internal ODataPayloadKind PayloadKind
         /// <param name="contentType">contentType</param>
         /// <param name="message">the message</param>
         /// <param name="expectedPayloadKind">expected payload kind.</param>
+        /// <param name="annotationsCache">The annotations cache used to store temporary metadata used for materialization of OData items.</param>
         /// <returns>atom materializer</returns>
         internal static MaterializeAtom Materialize(
             ResponseInfo responseInfo,
diff --git a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
index be2e6e2bbf..991ca74272 100644
--- a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
+++ b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
@@ -27,6 +27,7 @@ internal class EntityTrackingAdapter
         /// <param name="mergeOption">The merge option.</param>
         /// <param name="model">The model.</param>
         /// <param name="context">The context.</param>
+        /// <param name="materializerContext">The materialization context used to retrieve materialization-related information.</param>
         internal EntityTrackingAdapter(EntityTrackerBase entityTracker, MergeOption mergeOption, ClientEdmModel model, DataServiceContext context, IODataMaterializerContext materializerContext)
         {
             this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker, materializerContext);
diff --git a/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs b/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
index 19815f4299..7db16572fb 100644
--- a/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
+++ b/src/Microsoft.OData.Client/Materialization/FeedAndEntryMaterializerAdapter.cs
@@ -39,7 +39,10 @@ internal class FeedAndEntryMaterializerAdapter
         /// <summary>The current entry.</summary>
         private ODataResource currentEntry;
 
-        private IODataMaterializerContext materializerContext;
+        /// <summary>
+        /// The materializer context.
+        /// </summary>
+        private readonly IODataMaterializerContext materializerContext;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FeedAndEntryMaterializerAdapter"/> class.
@@ -48,6 +51,7 @@ internal class FeedAndEntryMaterializerAdapter
         /// <param name="reader">The reader.</param>
         /// <param name="model">The model.</param>
         /// <param name="mergeOption">The mergeOption.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption, IODataMaterializerContext materializerContext)
             : this(ODataUtils.GetReadFormat(messageReader), reader, model, mergeOption, materializerContext)
         {
@@ -60,6 +64,7 @@ internal FeedAndEntryMaterializerAdapter(ODataMessageReader messageReader, OData
         /// <param name="reader">The reader.</param>
         /// <param name="model">The model.</param>
         /// <param name="mergeOption">The mergeOption.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         internal FeedAndEntryMaterializerAdapter(ODataFormat odataFormat, ODataReaderWrapper reader, ClientEdmModel model, MergeOption mergeOption, IODataMaterializerContext materializerContext)
         {
             this.readODataFormat = odataFormat;
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs b/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
index 0106ea7ef8..224c56d5cc 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerEntry.cs
@@ -224,6 +224,7 @@ public static MaterializerEntry CreateEmpty()
         /// <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>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>A new materializer entry.</returns>
         public static MaterializerEntry CreateEntry(ODataResource entry, ODataFormat format, bool isTracking, ClientEdmModel model, IODataMaterializerContext materializerContext)
         {
@@ -251,6 +252,7 @@ public static MaterializerEntry CreateEntryForLoadProperty(EntityDescriptor desc
         /// Gets an entry for a given ODataResource.
         /// </summary>
         /// <param name="entry">The ODataResource.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer entry</returns>
         public static MaterializerEntry GetEntry(ODataResource entry, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs b/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
index adf624e3bf..cddbe97150 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerFeed.cs
@@ -67,6 +67,7 @@ public Uri NextPageLink
         /// </summary>
         /// <param name="feed">The feed.</param>
         /// <param name="entries">The entries.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer feed.</returns>
         public static MaterializerFeed CreateFeed(ODataResourceSet feed, IEnumerable<ODataResource> entries, IODataMaterializerContext materializerContext)
         {
@@ -87,6 +88,7 @@ public static MaterializerFeed CreateFeed(ODataResourceSet feed, IEnumerable<ODa
         /// Gets the materializer feed.
         /// </summary>
         /// <param name="feed">The feed.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer feed.</returns>
         public static MaterializerFeed GetFeed(ODataResourceSet feed, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs b/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
index ec4b360b14..9ad1c49d4d 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerNavigationLink.cs
@@ -63,10 +63,12 @@ public ODataResourceSet Feed
         /// </summary>
         /// <param name="link">The link.</param>
         /// <param name="entry">The entry.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer link.</returns>
         public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, MaterializerEntry entry, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null, "there should be no MaterializerNestedResourceInfo annotation on the entry link yet");
+            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null,
+                "there should be no MaterializerNestedResourceInfo annotation on the entry link yet");
             MaterializerNavigationLink materializedNestedResourceInfo = new MaterializerNavigationLink(link, entry);
             materializerContext.SetAnnotation<MaterializerNavigationLink>(link, materializedNestedResourceInfo);
             return materializedNestedResourceInfo;
@@ -77,10 +79,12 @@ public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link
         /// </summary>
         /// <param name="link">The link.</param>
         /// <param name="resourceSet">The resource set.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer link.</returns>
         public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link, ODataResourceSet resourceSet, IODataMaterializerContext materializerContext)
         {
-            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null, "there should be no MaterializerNestedResourceInfo annotation on the feed link yet");
+            Debug.Assert(materializerContext.GetAnnotation<MaterializerNavigationLink>(link) == null,
+                "there should be no MaterializerNestedResourceInfo annotation on the feed link yet");
             MaterializerNavigationLink materializedNestedResourceInfo = new MaterializerNavigationLink(link, resourceSet);
             materializerContext.SetAnnotation<MaterializerNavigationLink>(link, materializedNestedResourceInfo);
             return materializedNestedResourceInfo;
@@ -90,6 +94,7 @@ public static MaterializerNavigationLink CreateLink(ODataNestedResourceInfo link
         /// Gets the materializer link.
         /// </summary>
         /// <param name="link">The link.</param>
+        /// <param name="materializerContext">The current materializer context.</param>
         /// <returns>The materializer link.</returns>
         public static MaterializerNavigationLink GetLink(ODataNestedResourceInfo link, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
index 318bcddde1..8ba5d5488f 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializer.cs
@@ -230,6 +230,7 @@ internal static ProjectionPlan CreatePlanForShallowMaterialization(Type lastSegm
         /// <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>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>Whether the specified <paramref name="path"/> is null.</returns>
         /// <remarks>
         /// This method will not instantiate entity types on the path.
@@ -384,6 +385,7 @@ internal static IEnumerable ProjectionSelect(
         /// <summary>Provides support for getting payload entries during projections.</summary>
         /// <param name="entry">Entry to get sub-entry from.</param>
         /// <param name="name">Name of sub-entry.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>The sub-entry (never null).</returns>
         internal static ODataResource ProjectionGetEntry(MaterializerEntry entry, string name, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
index 046ef198c7..4a9e4b4372 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataEntityMaterializerInvoker.cs
@@ -52,6 +52,7 @@ internal static List<TTarget> ListAsElementType<T, TTarget>(object materializer,
         /// <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>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>Whether the specified <paramref name="path"/> is null.</returns>
         /// <remarks>
         /// This method will not instantiate entity types on the path.
@@ -93,6 +94,7 @@ internal static IEnumerable ProjectionSelect(
         /// <summary>Provides support for getting payload entries during projections.</summary>
         /// <param name="entry">Entry to get sub-entry from.</param>
         /// <param name="name">Name of sub-entry.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>The sub-entry (never null).</returns>
         internal static object ProjectionGetEntry(object entry, string name, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
index 713b2673e7..a48beae608 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
@@ -18,6 +18,7 @@ internal static class ODataItemExtensions
         /// Gets the materialized value.
         /// </summary>
         /// <param name="property">The property.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>The materialized value.</returns>
         public static object GetMaterializedValue(this ODataProperty property, IODataMaterializerContext materializerContext)
         {
@@ -29,6 +30,7 @@ public static object GetMaterializedValue(this ODataProperty property, IODataMat
         /// Determines whether a value has been materialized.
         /// </summary>
         /// <param name="property">The property.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns><c>true</c> if the value has been materialized; otherwise, <c>false</c>.</returns>
         public static bool HasMaterializedValue(this ODataProperty property, IODataMaterializerContext materializerContext)
         {
@@ -40,7 +42,8 @@ public static bool HasMaterializedValue(this ODataProperty property, IODataMater
         /// Sets the materialized value.
         /// </summary>
         /// <param name="property">The property.</param>
-        /// <param name="materializedValue">The materialized value.</param>
+        /// <param name="materializedValue">The materializer value.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         public static void SetMaterializedValue(this ODataProperty property, object materializedValue, IODataMaterializerContext materializerContext)
         {
             ODataAnnotatable annotatableObject = property.Value as ODataAnnotatable ?? property;
@@ -51,10 +54,11 @@ public static void SetMaterializedValue(this ODataProperty property, object mate
         /// Gets the materialized value.
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>The materialized value</returns>
         private static object GetMaterializedValueCore(ODataAnnotatable annotatableObject, IODataMaterializerContext materializerContext)
         {
-            MaterializerPropertyValue value = materializerContext.GetAnnotation<MaterializerPropertyValue>(annotatableObject);
+            MaterializerPropertyValue value = materializerContext.AnnotationsCache.GetAnnotation<MaterializerPropertyValue>(annotatableObject);
             Debug.Assert(value != null, "MaterializedValue not set");
             return value.Value;
         }
@@ -63,6 +67,7 @@ private static object GetMaterializedValueCore(ODataAnnotatable annotatableObjec
         /// Determines whether a value has been materialized.
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns><c>true</c> if the value has been materialized; otherwise, <c>false</c>.</returns>
         private static bool HasMaterializedValueCore(ODataAnnotatable annotatableObject, IODataMaterializerContext materializerContext)
         {
@@ -74,6 +79,7 @@ private static bool HasMaterializedValueCore(ODataAnnotatable annotatableObject,
         /// </summary>
         /// <param name="annotatableObject">The annotatable object.</param>
         /// <param name="materializedValue">The materialized value.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         private static void SetMaterializedValueCore(ODataAnnotatable annotatableObject, object materializedValue, IODataMaterializerContext materializerContext)
         {
             MaterializerPropertyValue materializerValue = new MaterializerPropertyValue { Value = materializedValue };
diff --git a/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
index f474624db7..7759e67388 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataReaderEntityMaterializer.cs
@@ -115,6 +115,7 @@ protected override ODataFormat Format
         /// <param name="message">the message for the payload</param>
         /// <param name="responseInfo">The current ResponseInfo object</param>
         /// <param name="expectedType">The expected type</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <returns>the MaterializerEntry that was read</returns>
         internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType, IODataMaterializerContext materializerContext)
         {
diff --git a/src/Microsoft.OData.Client/MaterializeFromAtom.cs b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
index 401a4e0a5b..f2fa5b85bb 100644
--- a/src/Microsoft.OData.Client/MaterializeFromAtom.cs
+++ b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
@@ -74,6 +74,7 @@ internal class MaterializeAtom : IDisposable, IEnumerable, IEnumerator
         /// <param name="plan">Projection plan (if compiled in an earlier query).</param>
         /// <param name="responseMessage">responseMessage</param>
         /// <param name="payloadKind">The kind of the payload to materialize.</param>
+        /// <param name="annotationsCache">The annotations cache used to store and retrieve temporary metadata used for materialization of OData items.</param>
         internal MaterializeAtom(
             ResponseInfo responseInfo,
             QueryComponents queryComponents,
@@ -102,6 +103,7 @@ internal MaterializeAtom(
         /// <param name="entries">entries that needs to be materialized.</param>
         /// <param name="elementType">result type.</param>
         /// <param name="format">The format of the response being materialized from.</param>
+        /// <param name="annotationsCache">The annotations cache used to store and retrieve temporary metadata used for materialization of OData items.</param>
         internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> entries, Type elementType, ODataFormat format, MaterializerAnnotationsCache annotationsCache)
         {
             this.responseInfo = responseInfo;
diff --git a/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs b/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
index 7f46be6a2e..9051246250 100644
--- a/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
+++ b/src/Microsoft.OData.Client/ProjectionPlanCompiler.cs
@@ -51,7 +51,10 @@ internal class ProjectionPlanCompiler : ALinqExpressionVisitor
         /// <summary>Whether the top level projection has been found.</summary>
         private bool topLevelProjectionFound;
 
-        IODataMaterializerContext materializerContext;
+        /// <summary>
+        /// The materializer context.
+        /// </summary>
+        private readonly IODataMaterializerContext materializerContext;
 
         #endregion Private fields
 
@@ -61,6 +64,7 @@ internal class ProjectionPlanCompiler : ALinqExpressionVisitor
         /// Initializes a new <see cref="ProjectionPlanCompiler"/> instance.
         /// </summary>
         /// <param name="normalizerRewrites">Rewrites introduces by normalizer.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         private ProjectionPlanCompiler(Dictionary<Expression, Expression> normalizerRewrites, IODataMaterializerContext materializerContext)
         {
             this.annotations = new Dictionary<Expression, ExpressionAnnotation>(ReferenceEqualityComparer<Expression>.Instance);

From 819ca9673c1173767dfaf45a7b53d93a3c33d1bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= <haby_habbes@live.com>
Date: Sat, 17 Sep 2022 19:09:49 +0300
Subject: [PATCH 09/16] Update
 src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs

Co-authored-by: Elizabeth Okerio <elizaokerio@gmail.com>
---
 .../Materialization/EntityTrackingAdapter.cs                   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
index 991ca74272..1f9b5b5f33 100644
--- a/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
+++ b/src/Microsoft.OData.Client/Materialization/EntityTrackingAdapter.cs
@@ -27,7 +27,8 @@ internal class EntityTrackingAdapter
         /// <param name="mergeOption">The merge option.</param>
         /// <param name="model">The model.</param>
         /// <param name="context">The context.</param>
-        /// <param name="materializerContext">The materialization context used to retrieve materialization-related information.</param>
+        /// <param name="materializerContext">The materialization context used to retrieve materialization related information.</param>
+
         internal EntityTrackingAdapter(EntityTrackerBase entityTracker, MergeOption mergeOption, ClientEdmModel model, DataServiceContext context, IODataMaterializerContext materializerContext)
         {
             this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker, materializerContext);

From e8c579219b52a5c8e95b592a87c9e93243bed7cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= <haby_habbes@live.com>
Date: Sat, 17 Sep 2022 19:18:13 +0300
Subject: [PATCH 10/16] Apply suggestions from code review

Co-authored-by: John Gathogo <john.gathogo@gmail.com>
---
 .../Materialization/MaterializerAnnotationsCache.cs | 13 ++++++-------
 .../MaterializerContextExtensions.cs                |  6 ++++--
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
index 5f8599f6b2..025a9de27e 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -11,19 +11,18 @@ namespace Microsoft.OData.Client.Materialization
 {
     /// <summary>
     /// A cache used to store temporary materialization metadata
-    /// for deseriliazed <see cref="ODataItem"/>s during materialization of response payloads
+    /// for deserialized <see cref="ODataItem"/>s during materialization of response payloads
+
     /// into client CLR objects. Keys are identified using reference equality.
     /// </summary>
     /// <remarks>
     /// Instances of the cache are not thread-safe. Each instance is expected to be used within the
     /// scope of a single request.
-    /// 
     /// The cache is designed to store one entry type per key. For example, if the key is
     /// an <see cref="ODataResource"/>, its value should be a <see cref="MaterializerEntry"/>. It also
     /// expects the value for any given key will not change.
-    /// So you should call `cache.SetAnnotation(odataResource, materializerEntry)` add the cache entry
+    /// For this reason, you should call `cache.SetAnnotation(odataResource, materializerEntry)` to add a cache entry
     /// and `cache.GetAnnotations<MaterializerEntry>(odataResource)` to retrieve the entry.
-    /// 
     /// If the requirements change such that we need to allow updating the value of a key to a different type,
     /// then the cache should be redesigned.
     /// </remarks>
@@ -33,7 +32,7 @@ internal sealed class MaterializerAnnotationsCache
 
         /// <summary>
         /// Adds an entry to the cache with the <paramref name="annotatable"/>
-        /// set as key,
+        /// set as key.
         /// </summary>
         /// <typeparam name="T">The type of the value.</typeparam>
         /// <param name="annotatable">The key of the entry.</param>
@@ -46,11 +45,11 @@ public void SetAnnotation<T>(ODataAnnotatable annotatable, T value) where T : cl
 
         /// <summary>
         /// Retrieves the value associated with the specified <paramref name="annotatable"/>.
-        /// Returns null if the cache does not contain an entry with the specifiedy key.
+        /// Returns null if the cache does not contain an entry with the specified key.
         /// </summary>
         /// <typeparam name="T">The expected type of the value.</typeparam>
         /// <param name="annotatable"></param>
-        /// <returns>The value associated with the specified <paramref name="annotatable"/> if the entry exists, or null otherwise.</returns>
+        /// <returns>The value associated with the specified <paramref name="annotatable"/> if the entry exists; otherwise null.</returns>
         public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
         {
             if (this.cache.TryGetValue(annotatable, out object value))
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
index 1a2c7b72c2..81ed8d029e 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
@@ -9,7 +9,8 @@ namespace Microsoft.OData.Client.Materialization
     internal static class MaterializerContextExtensions
     {
         /// <summary>
-        /// Associates the specified annotation <paramref name="value"/> with the specified
+        /// Associates the specified <paramref name="value"/> with the specified
+
         /// <paramref name="annotatable"/> to store metadata used for materialization.
         /// </summary>
         /// <typeparam name="T">The type of the value.</typeparam>
@@ -22,7 +23,8 @@ public static void SetAnnotation<T>(this IODataMaterializerContext context, ODat
         }
 
         /// <summary>
-        /// Retrieves the annotation value associated with te specified <paramref name="annotatable"/>.
+        /// Retrieves the value associated with the specified <paramref name="annotatable"/>.
+
         /// </summary>
         /// <typeparam name="T">The expected type of the annotation value.</typeparam>
         /// <param name="context">The materializer context.</param>

From 13ced4dc60d716feba419be49092430516474088 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Sat, 17 Sep 2022 19:37:03 +0300
Subject: [PATCH 11/16] Implement review suggestions

---
 src/Microsoft.OData.Client/BaseSaveResult.cs  |  1 -
 .../DataServiceRequest.cs                     |  1 -
 .../MaterializerAnnotationsCache.cs           |  2 +-
 .../MaterializeFromAtom.cs                    |  6 +++---
 ...ataServiceContextNoTrackingStreamsTests.cs |  2 +-
 ...ializationPolicyForComplexResourceTests.cs | 20 +++++++++----------
 6 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/Microsoft.OData.Client/BaseSaveResult.cs b/src/Microsoft.OData.Client/BaseSaveResult.cs
index 5f44c01272..247c8c163b 100644
--- a/src/Microsoft.OData.Client/BaseSaveResult.cs
+++ b/src/Microsoft.OData.Client/BaseSaveResult.cs
@@ -19,7 +19,6 @@ namespace Microsoft.OData.Client
     using System.Text;
     using System.Threading;
     using Microsoft.OData;
-    using Microsoft.OData.Client.Materialization;
     using Microsoft.OData.Client.Metadata;
 
     #endregion Namespaces
diff --git a/src/Microsoft.OData.Client/DataServiceRequest.cs b/src/Microsoft.OData.Client/DataServiceRequest.cs
index 273202ee4f..d68b3105de 100644
--- a/src/Microsoft.OData.Client/DataServiceRequest.cs
+++ b/src/Microsoft.OData.Client/DataServiceRequest.cs
@@ -79,7 +79,6 @@ internal static MaterializeAtom Materialize(
             {
                 return MaterializeAtom.EmptyResults;
             }
-
             
             return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind, annotationsCache);
         }
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
index 025a9de27e..8911320329 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
@@ -48,7 +48,7 @@ public void SetAnnotation<T>(ODataAnnotatable annotatable, T value) where T : cl
         /// Returns null if the cache does not contain an entry with the specified key.
         /// </summary>
         /// <typeparam name="T">The expected type of the value.</typeparam>
-        /// <param name="annotatable"></param>
+        /// <param name="annotatable">The key of the entry.</param>
         /// <returns>The value associated with the specified <paramref name="annotatable"/> if the entry exists; otherwise null.</returns>
         public T GetAnnotation<T>(ODataAnnotatable annotatable) where T: class
         {
diff --git a/src/Microsoft.OData.Client/MaterializeFromAtom.cs b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
index f2fa5b85bb..aff289e1d3 100644
--- a/src/Microsoft.OData.Client/MaterializeFromAtom.cs
+++ b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
@@ -113,9 +113,9 @@ internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> e
             Type implementationType;
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
             QueryComponents qc = new QueryComponents(null, Util.ODataVersionEmpty, elementType, null, null);
-            ODataMaterializerContext context = new ODataMaterializerContext(responseInfo, annotationsCache);
-            EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, context);
-            this.materializer = new ODataEntriesEntityMaterializer(entries, context, entityTrackingAdapter, qc, materializerType, null, format);
+            ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, annotationsCache);
+            EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, materializerContext);
+            this.materializer = new ODataEntriesEntityMaterializer(entries, materializerContext, entityTrackingAdapter, qc, materializerType, null, format);
         }
 
         /// <summary>
diff --git a/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs b/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
index 12cf8e1486..9dc9718aad 100644
--- a/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
+++ b/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
@@ -234,7 +234,7 @@ public void TestAddingNewItemsBehaviourShouldBeUnAltered()
             Assert.NotNull(NonTrackingContext.GetEntityDescriptor(user));
             Assert.NotNull(DefaultTrackingContext.GetEntityDescriptor(user));
 
-            SaveContextChanges(new DataServiceContext[] { DefaultTrackingContext, NonTrackingContext });
+            SaveContextChanges(new DataServiceContext[] { DefaultTrackingContext });//, NonTrackingContext });
             Assert.Single(DefaultTrackingContext.Entities);
             Assert.Single(NonTrackingContext.Entities);
         }
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
index 8652bd87a5..07e8c782d3 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
@@ -50,7 +50,7 @@ public void ComplexWithPrimitiveValueShouldMaterialize()
         [Fact]
         public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
             CollectionValueMaterializationPolicyTests.Point point = new CollectionValueMaterializationPolicyTests.Point();
             ODataProperty property = new ODataProperty() { Name = "Z", Value = 10 };
             this.CreateEntryMaterializationPolicy(context)
@@ -60,7 +60,7 @@ public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         [Fact]
         public void ApplyNullOnCollectionPropertyShouldError()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = null };
 
@@ -71,7 +71,7 @@ public void ApplyNullOnCollectionPropertyShouldError()
         [Fact]
         public void ApplyStringValueForCollectionPropertyShouldError()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = "foo" };
 
@@ -83,7 +83,7 @@ public void ApplyStringValueForCollectionPropertyShouldError()
         public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         {
             var annotationsCache = new MaterializerAnnotationsCache();
-            TestMaterializerContext context = new TestMaterializerContext(annotationsCache);
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(annotationsCache);
 
             //In a true client, a TypeResolver will be used to resolve derived property type.
             context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
@@ -110,7 +110,7 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyDerivedComplexForBaseComplexTypeProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
 
             context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
@@ -141,7 +141,7 @@ public void ApplyDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
 
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings.Add("ShouldBeCleared");
@@ -157,7 +157,7 @@ public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         [Fact]
         public void ApplyODataCollectionValueToNullCollectionProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings = null;
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = new ODataCollectionValue() { Items = new string[] { "foo" }, TypeName = typeof(ComplexTypeWithPrimitiveCollection).FullName } };
@@ -172,7 +172,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         {
             foreach (var startingPropertyState in new ChildComplexType[] { null, new ChildComplexType() })
             {
-                TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+                TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
                 ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
                 complexInstance.InnerComplexProperty = startingPropertyState;
                 var innerEntry = new ODataResource() { Properties = new ODataProperty[] { new ODataProperty() { Name = "Prop", Value = 1 } } };
@@ -184,7 +184,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         [Fact]
         public void NullValueShouldBeAppliedToSubComplexValueProperty()
         {
-            TestMaterializerContext context = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
             ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
             complexInstance.InnerComplexProperty = new ChildComplexType();
 
@@ -192,7 +192,7 @@ public void NullValueShouldBeAppliedToSubComplexValueProperty()
             Assert.Null(complexInstance.InnerComplexProperty);
         }
 
-        private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext context = null)
+        private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext  materializerContext = null)
         {
             context = context ?? new TestMaterializerContext(new MaterializerAnnotationsCache());
             var resource = new ODataResource() { TypeName = "ComplexTypeWithChildComplexType", Properties = new ODataProperty[0] };

From f52c0a0d4992a627058c64f66e369c84b33a3370 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Sat, 17 Sep 2022 19:41:10 +0300
Subject: [PATCH 12/16] Remove whitespace

---
 src/Microsoft.OData.Client/DataServiceRequest.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Microsoft.OData.Client/DataServiceRequest.cs b/src/Microsoft.OData.Client/DataServiceRequest.cs
index d68b3105de..8691177c80 100644
--- a/src/Microsoft.OData.Client/DataServiceRequest.cs
+++ b/src/Microsoft.OData.Client/DataServiceRequest.cs
@@ -79,7 +79,7 @@ internal static MaterializeAtom Materialize(
             {
                 return MaterializeAtom.EmptyResults;
             }
-            
+
             return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind, annotationsCache);
         }
 

From a08b019768c9d599c80bb29cc291e0eeefbd96b4 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Sat, 17 Sep 2022 19:48:32 +0300
Subject: [PATCH 13/16] Use materializerContext parameter name instead of
 context

---
 .../CollectionValueMaterializationPolicy.cs        |  6 +++---
 .../EntryValueMaterializationPolicy.cs             |  6 +++---
 .../EnumValueMaterializationPolicy.cs              | 14 +++++++-------
 .../MaterializerContextExtensions.cs               | 14 ++++++--------
 .../ODataMessageReaderMaterializer.cs              |  6 +++---
 .../PrimitiveValueMaterializationPolicy.cs         | 12 ++++++------
 6 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
index dd559d54ce..6e70cf9d51 100644
--- a/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/CollectionValueMaterializationPolicy.cs
@@ -34,11 +34,11 @@ internal class CollectionValueMaterializationPolicy : MaterializationPolicy
         /// <summary>
         /// Initializes a new instance of the <see cref="CollectionValueMaterializationPolicy" /> class.
         /// </summary>
-        /// <param name="context">The context.</param>
+        /// <param name="materializerContext">The context.</param>
         /// <param name="primitivePolicy">The primitive policy.</param>
-        internal CollectionValueMaterializationPolicy(IODataMaterializerContext context, PrimitiveValueMaterializationPolicy primitivePolicy)
+        internal CollectionValueMaterializationPolicy(IODataMaterializerContext materializerContext, PrimitiveValueMaterializationPolicy primitivePolicy)
         {
-            this.materializerContext = context;
+            this.materializerContext = materializerContext;
             this.primitiveValueMaterializationPolicy = primitivePolicy;
         }
 
diff --git a/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
index 1d58a28020..642cfff103 100644
--- a/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/EntryValueMaterializationPolicy.cs
@@ -30,16 +30,16 @@ internal class EntryValueMaterializationPolicy : StructuralValueMaterializationP
         /// <summary>
         /// Initializes a new instance of the <see cref="EntryValueMaterializationPolicy" /> class.
         /// </summary>
-        /// <param name="context">The context.</param>
+        /// <param name="materializerContext">The context.</param>
         /// <param name="entityTrackingAdapter">The entity tracking adapter.</param>
         /// <param name="lazyPrimitivePropertyConverter">The lazy primitive property converter.</param>
         /// <param name="nextLinkTable">The next link table.</param>
         internal EntryValueMaterializationPolicy(
-            IODataMaterializerContext context,
+            IODataMaterializerContext materializerContext,
             EntityTrackingAdapter entityTrackingAdapter,
             DSClient.SimpleLazy<PrimitivePropertyConverter> lazyPrimitivePropertyConverter,
             Dictionary<IEnumerable, DataServiceQueryContinuation> nextLinkTable)
-            : base(context, lazyPrimitivePropertyConverter)
+            : base(materializerContext, lazyPrimitivePropertyConverter)
         {
             this.nextLinkTable = nextLinkTable;
             this.EntityTrackingAdapter = entityTrackingAdapter;
diff --git a/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
index e5a6f5e314..a0c6562685 100644
--- a/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/EnumValueMaterializationPolicy.cs
@@ -18,15 +18,15 @@ namespace Microsoft.OData.Client.Materialization
     internal class EnumValueMaterializationPolicy
     {
         /// <summary> MaterializerContext used to resolve types for materialization. </summary>
-        private readonly IODataMaterializerContext context;
+        private readonly IODataMaterializerContext materializerContext;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="EnumValueMaterializationPolicy" /> class.
         /// </summary>
-        /// <param name="context">The context.</param>
-        internal EnumValueMaterializationPolicy(IODataMaterializerContext context)
+        /// <param name="materializerContext">The materializer context.</param>
+        internal EnumValueMaterializationPolicy(IODataMaterializerContext materializerContext)
         {
-            this.context = context;
+            this.materializerContext = materializerContext;
         }
 
         /// <summary>
@@ -40,9 +40,9 @@ public object MaterializeEnumTypeProperty(Type valueType, ODataProperty property
             object materializedValue = null;
             ODataEnumValue value = property.Value as ODataEnumValue;
             this.MaterializeODataEnumValue(valueType, value.TypeName, value.Value, () => "TODO: Is this reachable?", out materializedValue);
-            if (!property.HasMaterializedValue(this.context))
+            if (!property.HasMaterializedValue(this.materializerContext))
             {
-                property.SetMaterializedValue(materializedValue, this.context);
+                property.SetMaterializedValue(materializedValue, this.materializerContext);
             }
 
             return materializedValue;
@@ -102,7 +102,7 @@ private void MaterializeODataEnumValue(Type type, string wireTypeName, string en
         {
             Debug.Assert(type != null, "type != null");
             Type underlyingType = Nullable.GetUnderlyingType(type) ?? type;
-            ClientTypeAnnotation elementTypeAnnotation = this.context.ResolveTypeForMaterialization(underlyingType, wireTypeName);
+            ClientTypeAnnotation elementTypeAnnotation = this.materializerContext.ResolveTypeForMaterialization(underlyingType, wireTypeName);
             Debug.Assert(elementTypeAnnotation != null, "elementTypeAnnotation != null");
 
             // TODO: Find better way to parse Enum
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
index 81ed8d029e..7921896f2e 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
@@ -10,29 +10,27 @@ internal static class MaterializerContextExtensions
     {
         /// <summary>
         /// Associates the specified <paramref name="value"/> with the specified
-
         /// <paramref name="annotatable"/> to store metadata used for materialization.
         /// </summary>
         /// <typeparam name="T">The type of the value.</typeparam>
-        /// <param name="context">The materializer context.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <param name="annotatable">The item to annotate.</param>
         /// <param name="value">The annotation value.</param>
-        public static void SetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable, T value) where T : class
+        public static void SetAnnotation<T>(this IODataMaterializerContext materializerContext, ODataAnnotatable annotatable, T value) where T : class
         {
-            context.AnnotationsCache.SetAnnotation(annotatable, value);
+            materializerContext.AnnotationsCache.SetAnnotation(annotatable, value);
         }
 
         /// <summary>
         /// Retrieves the value associated with the specified <paramref name="annotatable"/>.
-
         /// </summary>
         /// <typeparam name="T">The expected type of the annotation value.</typeparam>
-        /// <param name="context">The materializer context.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <param name="annotatable">The item for which to retrieve the annotation.</param>
         /// <returns>The annotation value associated with the <paramref name="annotatable"/> if it exists, or null otherwise.</returns>
-        public static T GetAnnotation<T>(this IODataMaterializerContext context, ODataAnnotatable annotatable) where T : class
+        public static T GetAnnotation<T>(this IODataMaterializerContext materializerContext, ODataAnnotatable annotatable) where T : class
         {
-            return context.AnnotationsCache.GetAnnotation<T>(annotatable);
+            return materializerContext.AnnotationsCache.GetAnnotation<T>(annotatable);
         }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMessageReaderMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataMessageReaderMaterializer.cs
index 61057d044a..cd3b21151d 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMessageReaderMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMessageReaderMaterializer.cs
@@ -32,11 +32,11 @@ internal abstract class ODataMessageReaderMaterializer : ODataMaterializer
         /// Initializes a new instance of the <see cref="ODataMessageReaderMaterializer"/> class.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="context">The materializer context.</param>
+        /// <param name="materializerContext">The materializer context.</param>
         /// <param name="expectedType">The expected type.</param>
         /// <param name="singleResult">The single result.</param>
-        public ODataMessageReaderMaterializer(ODataMessageReader reader, IODataMaterializerContext context, Type expectedType, bool? singleResult)
-            : base(context, expectedType)
+        public ODataMessageReaderMaterializer(ODataMessageReader reader, IODataMaterializerContext materializerContext, Type expectedType, bool? singleResult)
+            : base(materializerContext, expectedType)
         {
             this.messageReader = reader;
             this.SingleResult = singleResult;
diff --git a/src/Microsoft.OData.Client/Materialization/PrimitiveValueMaterializationPolicy.cs b/src/Microsoft.OData.Client/Materialization/PrimitiveValueMaterializationPolicy.cs
index 034f3b3bb5..707452cca0 100644
--- a/src/Microsoft.OData.Client/Materialization/PrimitiveValueMaterializationPolicy.cs
+++ b/src/Microsoft.OData.Client/Materialization/PrimitiveValueMaterializationPolicy.cs
@@ -17,7 +17,7 @@ namespace Microsoft.OData.Client.Materialization
     internal class PrimitiveValueMaterializationPolicy
     {
         /// <summary> MaterializerContext used to resolve types for materialization. </summary>
-        private readonly IODataMaterializerContext context;
+        private readonly IODataMaterializerContext materializerContext;
 
         /// <summary>
         /// primitive property converter used to convert the property have the value has been materialized. </summary>
@@ -26,11 +26,11 @@ internal class PrimitiveValueMaterializationPolicy
         /// <summary>
         /// Initializes a new instance of the <see cref="PrimitiveValueMaterializationPolicy" /> class.
         /// </summary>
-        /// <param name="context">The context.</param>
+        /// <param name="materializerContext">The context.</param>
         /// <param name="lazyPrimitivePropertyConverter">The lazy primitive property converter.</param>
-        internal PrimitiveValueMaterializationPolicy(IODataMaterializerContext context, SimpleLazy<PrimitivePropertyConverter> lazyPrimitivePropertyConverter)
+        internal PrimitiveValueMaterializationPolicy(IODataMaterializerContext materializerContext, SimpleLazy<PrimitivePropertyConverter> lazyPrimitivePropertyConverter)
         {
-            this.context = context;
+            this.materializerContext = materializerContext;
             this.lazyPrimitivePropertyConverter = lazyPrimitivePropertyConverter;
         }
 
@@ -92,7 +92,7 @@ private void MaterializePrimitiveDataValue(Type type, string wireTypeName, objec
             bool knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype);
             if (!knownType)
             {
-                nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName);
+                nestedElementType = this.materializerContext.ResolveTypeForMaterialization(type, wireTypeName);
                 Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw");
                 knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype);
             }
@@ -112,7 +112,7 @@ private void MaterializePrimitiveDataValue(Type type, string wireTypeName, objec
                 {
                     ODataUntypedValue untypedVal = value as ODataUntypedValue;
                     if ((untypedVal != null)
-                        && this.context.UndeclaredPropertyBehavior == UndeclaredPropertyBehavior.Support)
+                        && this.materializerContext.UndeclaredPropertyBehavior == UndeclaredPropertyBehavior.Support)
                     {
                         value = CommonUtil.ParseJsonToPrimitiveValue(untypedVal.RawValue);
                     }

From 3c9745f3a97aa7298d1c43831688d21699c6430c Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Sat, 17 Sep 2022 20:17:14 +0300
Subject: [PATCH 14/16] Fix build errors

---
 ...ializationPolicyForComplexResourceTests.cs | 46 +++++++++----------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
index 07e8c782d3..3ab8301b14 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
@@ -53,8 +53,8 @@ public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
             TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
             CollectionValueMaterializationPolicyTests.Point point = new CollectionValueMaterializationPolicyTests.Point();
             ODataProperty property = new ODataProperty() { Name = "Z", Value = 10 };
-            this.CreateEntryMaterializationPolicy(context)
-                .ApplyDataValue(context.ResolveTypeForMaterialization(typeof(CollectionValueMaterializationPolicyTests.Point), null), property, point);
+            this.CreateEntryMaterializationPolicy(materializerContext)
+                .ApplyDataValue(materializerContext.ResolveTypeForMaterialization(typeof(CollectionValueMaterializationPolicyTests.Point), null), property, point);
         }
 
         [Fact]
@@ -64,7 +64,7 @@ public void ApplyNullOnCollectionPropertyShouldError()
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = null };
 
-            Action test = () => this.CreateEntryMaterializationPolicy(context).ApplyDataValue(context.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
+            Action test = () => this.CreateEntryMaterializationPolicy(materializerContext).ApplyDataValue(materializerContext.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
             test.ShouldThrow<InvalidOperationException>().WithMessage(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name));
         }
 
@@ -75,7 +75,7 @@ public void ApplyStringValueForCollectionPropertyShouldError()
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = "foo" };
 
-            Action test = () => this.CreateEntryMaterializationPolicy(context).ApplyDataValue(context.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
+            Action test = () => this.CreateEntryMaterializationPolicy(materializerContext).ApplyDataValue(materializerContext.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
             test.ShouldThrow<InvalidOperationException>().WithMessage(DSClient.Strings.Deserialize_MixedTextWithComment);
         }
 
@@ -86,10 +86,10 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
             TestMaterializerContext  materializerContext = new TestMaterializerContext(annotationsCache);
 
             //In a true client, a TypeResolver will be used to resolve derived property type.
-            context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
+            materializerContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
-                var edmType = context.Model.GetOrCreateEdmType(typeof(DerivedComplexType));
-                return new ClientTypeAnnotation(edmType, typeof(DerivedComplexType), "DerivedComplexType", context.Model);
+                var edmType = materializerContext.Model.GetOrCreateEdmType(typeof(DerivedComplexType));
+                return new ClientTypeAnnotation(edmType, typeof(DerivedComplexType), "DerivedComplexType", materializerContext.Model);
             };
 
             var derivedResource = new ODataResource()
@@ -99,8 +99,8 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
             };
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
-            var materializerEntry = MaterializerEntry.CreateEntry(derivedResource, ODataFormat.Json, true, clientEdmModel, context);
-            this.CreateEntryMaterializationPolicy(context).Materialize(materializerEntry, typeof(ChildComplexType), false);
+            var materializerEntry = MaterializerEntry.CreateEntry(derivedResource, ODataFormat.Json, true, clientEdmModel, materializerContext);
+            this.CreateEntryMaterializationPolicy(materializerContext).Materialize(materializerEntry, typeof(ChildComplexType), false);
 
             var derived = materializerEntry.ResolvedObject as DerivedComplexType;
             Assert.NotNull(derived);
@@ -112,17 +112,17 @@ public void ApplyDerivedComplexForBaseComplexTypeProperty()
         {
             TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
 
-            context.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
+            materializerContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
                 if (name == "DerivedComplexType")
                 {
-                    var edmType = context.Model.GetOrCreateEdmType(typeof(DerivedComplexType));
-                    return new ClientTypeAnnotation(edmType, typeof(DerivedComplexType), "DerivedComplexType", context.Model);
+                    var edmType = materializerContext.Model.GetOrCreateEdmType(typeof(DerivedComplexType));
+                    return new ClientTypeAnnotation(edmType, typeof(DerivedComplexType), "DerivedComplexType", materializerContext.Model);
                 }
                 else
                 {
-                    var edmType = context.Model.GetOrCreateEdmType(typeof(ComplexTypeWithChildComplexType));
-                    return new ClientTypeAnnotation(edmType, typeof(ComplexTypeWithChildComplexType), "ComplexTypeWithChildComplexType", context.Model);
+                    var edmType = materializerContext.Model.GetOrCreateEdmType(typeof(ComplexTypeWithChildComplexType));
+                    return new ClientTypeAnnotation(edmType, typeof(ComplexTypeWithChildComplexType), "ComplexTypeWithChildComplexType", materializerContext.Model);
                 }
             };
             ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
@@ -133,7 +133,7 @@ public void ApplyDerivedComplexForBaseComplexTypeProperty()
                 TypeName = "DerivedComplexType",
                 Properties = new ODataProperty[] { new ODataProperty { Name = "DerivedProp", Value = 2 } }
             };
-            this.ApplyInnerProperty(innerResource, complexInstance, context);
+            this.ApplyInnerProperty(innerResource, complexInstance, materializerContext);
 
             Assert.Equal(2, (complexInstance.InnerComplexProperty as DerivedComplexType).DerivedProp);
         }
@@ -147,9 +147,9 @@ public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
             complexInstance.Strings.Add("ShouldBeCleared");
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = new ODataCollectionValue() };
 
-            this.CreateEntryMaterializationPolicy(context)
+            this.CreateEntryMaterializationPolicy(materializerContext)
                 .ApplyDataValue(
-                context.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null),
+                materializerContext.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null),
                 property, complexInstance);
             complexInstance.Strings.Should().HaveCount(0);
         }
@@ -162,7 +162,7 @@ public void ApplyODataCollectionValueToNullCollectionProperty()
             complexInstance.Strings = null;
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = new ODataCollectionValue() { Items = new string[] { "foo" }, TypeName = typeof(ComplexTypeWithPrimitiveCollection).FullName } };
 
-            this.CreateEntryMaterializationPolicy(context).ApplyDataValue(context.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
+            this.CreateEntryMaterializationPolicy(materializerContext).ApplyDataValue(materializerContext.ResolveTypeForMaterialization(typeof(ComplexTypeWithPrimitiveCollection), null), property, complexInstance);
             complexInstance.Strings.Should().HaveCount(1);
             complexInstance.Strings[0].Should().Be("foo");
         }
@@ -194,28 +194,28 @@ public void NullValueShouldBeAppliedToSubComplexValueProperty()
 
         private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext  materializerContext = null)
         {
-            context = context ?? new TestMaterializerContext(new MaterializerAnnotationsCache());
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache());
             var resource = new ODataResource() { TypeName = "ComplexTypeWithChildComplexType", Properties = new ODataProperty[0] };
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
-            var materializerEntry = MaterializerEntry.CreateEntry(resource, ODataFormat.Json, false, clientEdmModel, context);
+            var materializerEntry = MaterializerEntry.CreateEntry(resource, ODataFormat.Json, false, clientEdmModel, materializerContext);
             materializerEntry.ResolvedObject = parentInstance;
             ODataNestedResourceInfo innerComplexP = new ODataNestedResourceInfo() { Name = "InnerComplexProperty", IsCollection = false };
 
             MaterializerEntry innerMaterializerEntry;
             if (innerResource != null)
             {
-                innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel, context);
+                innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel, materializerContext);
             }
             else
             {
                 innerMaterializerEntry = MaterializerEntry.CreateEmpty();
             }
 
-            MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry, context);
+            MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry, materializerContext);
             materializerEntry.AddNestedResourceInfo(innerComplexP);
 
-            var policy = this.CreateEntryMaterializationPolicy(context);
+            var policy = this.CreateEntryMaterializationPolicy(materializerContext);
             policy.EntityTrackingAdapter.TargetInstance = parentInstance;
             policy.Materialize(materializerEntry, typeof(ComplexTypeWithChildComplexType), true);
         }

From b208a03938408d21d8b3d4bf62cbb51b362f5ea9 Mon Sep 17 00:00:00 2001
From: Clement Habinshuti <clhabins@microsoft.com>
Date: Sat, 17 Sep 2022 22:36:38 +0300
Subject: [PATCH 15/16] Rename MaterializerAnnotationsCache to
 MaterializerCache

---
 src/Microsoft.OData.Client/BaseAsyncResult.cs |  4 +--
 src/Microsoft.OData.Client/BatchSaveResult.cs |  4 +--
 .../DataServiceRequest.cs                     |  6 ++--
 .../IODataMaterializerContext.cs              |  6 +++-
 ...notationsCache.cs => MaterializerCache.cs} |  5 ++--
 .../MaterializerContextExtensions.cs          |  4 +--
 .../Materialization/ODataItemExtensions.cs    |  2 +-
 .../Materialization/ODataMaterializer.cs      |  5 ++--
 .../ODataMaterializerContext.cs               |  8 ++++--
 .../MaterializeFromAtom.cs                    | 12 ++++----
 src/Microsoft.OData.Client/QueryResult.cs     |  2 +-
 src/Microsoft.OData.Client/SaveResult.cs      |  4 +--
 ...ataServiceContextNoTrackingStreamsTests.cs |  2 +-
 .../Tests/DataServiceRequestTests.cs          |  4 +--
 ...llectionValueMaterializationPolicyTests.cs | 10 +++----
 ...ializationPolicyForComplexResourceTests.cs | 28 +++++++++----------
 ...ntryValueMaterializationPolicyUnitTests.cs |  2 +-
 ...eedAndEntryMaterializerAdapterUnitTests.cs |  2 +-
 .../Materialization/MaterializerEntryTests.cs |  2 +-
 .../ODataEntityMaterializerUnitTests.cs       |  2 +-
 ...ODataEntriesEntityMaterializerUnitTests.cs |  2 +-
 ...rimitiveValueMaterializationPolicyTests.cs |  2 +-
 .../TestMaterializerContext.cs                |  6 ++--
 .../Tests/T4/ODataT4CamelCaseTests.cs         |  8 +++---
 24 files changed, 69 insertions(+), 63 deletions(-)
 rename src/Microsoft.OData.Client/Materialization/{MaterializerAnnotationsCache.cs => MaterializerCache.cs} (94%)

diff --git a/src/Microsoft.OData.Client/BaseAsyncResult.cs b/src/Microsoft.OData.Client/BaseAsyncResult.cs
index 323c792089..6d9140043b 100644
--- a/src/Microsoft.OData.Client/BaseAsyncResult.cs
+++ b/src/Microsoft.OData.Client/BaseAsyncResult.cs
@@ -28,9 +28,9 @@ internal abstract class BaseAsyncResult : IAsyncResult
         protected PerRequest perRequest;
 
         /// <summary>
-        /// Cache used to store temporary metadata for OData items during materialization.
+        /// Cache used to store temporary metadata used for materialization of OData items.
         /// </summary>
-        protected MaterializerAnnotationsCache annotationsCache = new MaterializerAnnotationsCache();
+        protected MaterializerCache materializerCache = new MaterializerCache();
 
         /// <summary>
         /// The int equivalent for true.
diff --git a/src/Microsoft.OData.Client/BatchSaveResult.cs b/src/Microsoft.OData.Client/BatchSaveResult.cs
index 6327a2b612..cd3a240a3c 100644
--- a/src/Microsoft.OData.Client/BatchSaveResult.cs
+++ b/src/Microsoft.OData.Client/BatchSaveResult.cs
@@ -254,7 +254,7 @@ protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescri
                 /*projectionPlan*/ null,
                 this.currentOperationResponse.CreateResponseMessage(),
                 ODataPayloadKind.Resource,
-                this.annotationsCache);
+                this.materializerCache);
         }
 
         /// <summary>
@@ -690,7 +690,7 @@ private IEnumerable<OperationResponse> HandleBatchResponse(ODataBatchReader batc
                                             this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                             this.currentOperationResponse.CreateResponseMessage(),
                                             query.PayloadKind,
-                                            this.annotationsCache);
+                                            this.materializerCache);
                                         qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                     }
                                 }
diff --git a/src/Microsoft.OData.Client/DataServiceRequest.cs b/src/Microsoft.OData.Client/DataServiceRequest.cs
index 8691177c80..e24e5978a0 100644
--- a/src/Microsoft.OData.Client/DataServiceRequest.cs
+++ b/src/Microsoft.OData.Client/DataServiceRequest.cs
@@ -60,7 +60,7 @@ internal ODataPayloadKind PayloadKind
         /// <param name="contentType">contentType</param>
         /// <param name="message">the message</param>
         /// <param name="expectedPayloadKind">expected payload kind.</param>
-        /// <param name="annotationsCache">The annotations cache used to store temporary metadata used for materialization of OData items.</param>
+        /// <param name="materializerCache">Cache used to store temporary metadata used for materialization of OData items.</param>
         /// <returns>atom materializer</returns>
         internal static MaterializeAtom Materialize(
             ResponseInfo responseInfo,
@@ -69,7 +69,7 @@ internal static MaterializeAtom Materialize(
             string contentType,
             IODataResponseMessage message,
             ODataPayloadKind expectedPayloadKind,
-            MaterializerAnnotationsCache annotationsCache)
+            MaterializerCache materializerCache)
         {
             Debug.Assert(queryComponents != null, "querycomponents");
             Debug.Assert(message != null, "message");
@@ -80,7 +80,7 @@ internal static MaterializeAtom Materialize(
                 return MaterializeAtom.EmptyResults;
             }
 
-            return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind, annotationsCache);
+            return new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind, materializerCache);
         }
 
         /// <summary>
diff --git a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
index edb4c7e90d..9f435bce90 100644
--- a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
@@ -53,6 +53,10 @@ internal interface IODataMaterializerContext
         /// <returns>The resolved EDM type to provide to ODataLib.</returns>
         IEdmType ResolveExpectedTypeForReading(Type clientClrType);
 
-        MaterializerAnnotationsCache AnnotationsCache { get;  }
+        /// <summary>
+        /// Used to store temporary metadata used to converter deserialized
+        /// OData items into CLR objects.
+        /// </summary>
+        MaterializerCache MaterializerCache { get; }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs b/src/Microsoft.OData.Client/Materialization/MaterializerCache.cs
similarity index 94%
rename from src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
rename to src/Microsoft.OData.Client/Materialization/MaterializerCache.cs
index 8911320329..fb8ddfa117 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerAnnotationsCache.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerCache.cs
@@ -1,5 +1,5 @@
 //---------------------------------------------------------------------
-// <copyright file="MaterializerAnnotationsCache.cs" company="Microsoft">
+// <copyright file="MaterializerCache.cs" company="Microsoft">
 //      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
 // </copyright>
 //---------------------------------------------------------------------
@@ -12,7 +12,6 @@ namespace Microsoft.OData.Client.Materialization
     /// <summary>
     /// A cache used to store temporary materialization metadata
     /// for deserialized <see cref="ODataItem"/>s during materialization of response payloads
-
     /// into client CLR objects. Keys are identified using reference equality.
     /// </summary>
     /// <remarks>
@@ -26,7 +25,7 @@ namespace Microsoft.OData.Client.Materialization
     /// If the requirements change such that we need to allow updating the value of a key to a different type,
     /// then the cache should be redesigned.
     /// </remarks>
-    internal sealed class MaterializerAnnotationsCache
+    internal sealed class MaterializerCache
     {
         private readonly Dictionary<ODataAnnotatable, object> cache = new Dictionary<ODataAnnotatable, object>(ReferenceEqualityComparer<ODataAnnotatable>.Instance);
 
diff --git a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
index 7921896f2e..31ad376af9 100644
--- a/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/MaterializerContextExtensions.cs
@@ -18,7 +18,7 @@ internal static class MaterializerContextExtensions
         /// <param name="value">The annotation value.</param>
         public static void SetAnnotation<T>(this IODataMaterializerContext materializerContext, ODataAnnotatable annotatable, T value) where T : class
         {
-            materializerContext.AnnotationsCache.SetAnnotation(annotatable, value);
+            materializerContext.MaterializerCache.SetAnnotation(annotatable, value);
         }
 
         /// <summary>
@@ -30,7 +30,7 @@ public static void SetAnnotation<T>(this IODataMaterializerContext materializerC
         /// <returns>The annotation value associated with the <paramref name="annotatable"/> if it exists, or null otherwise.</returns>
         public static T GetAnnotation<T>(this IODataMaterializerContext materializerContext, ODataAnnotatable annotatable) where T : class
         {
-            return materializerContext.AnnotationsCache.GetAnnotation<T>(annotatable);
+            return materializerContext.MaterializerCache.GetAnnotation<T>(annotatable);
         }
     }
 }
diff --git a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
index a48beae608..309211ea46 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataItemExtensions.cs
@@ -58,7 +58,7 @@ public static void SetMaterializedValue(this ODataProperty property, object mate
         /// <returns>The materialized value</returns>
         private static object GetMaterializedValueCore(ODataAnnotatable annotatableObject, IODataMaterializerContext materializerContext)
         {
-            MaterializerPropertyValue value = materializerContext.AnnotationsCache.GetAnnotation<MaterializerPropertyValue>(annotatableObject);
+            MaterializerPropertyValue value = materializerContext.MaterializerCache.GetAnnotation<MaterializerPropertyValue>(annotatableObject);
             Debug.Assert(value != null, "MaterializedValue not set");
             return value.Value;
         }
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
index 91f2f98d12..f1bbf7e73d 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializer.cs
@@ -184,6 +184,7 @@ protected PrimitiveValueMaterializationPolicy PrimitiveValueMaterializier
         /// <param name="queryComponents">The query components for the request.</param>
         /// <param name="plan">The projection plan.</param>
         /// <param name="payloadKind">expected payload kind.</param>
+        /// <param name="materializerCache">The materializer cache.</param>
         /// <returns>A materializer specialized for the given response.</returns>
         public static ODataMaterializer CreateMaterializerForMessage(
             IODataResponseMessage responseMessage,
@@ -192,7 +193,7 @@ public static ODataMaterializer CreateMaterializerForMessage(
             QueryComponents queryComponents,
             ProjectionPlan plan,
             ODataPayloadKind payloadKind,
-            MaterializerAnnotationsCache annotationsCache)
+            MaterializerCache materializerCache)
         {
             ODataMessageReader messageReader = CreateODataMessageReader(responseMessage, responseInfo, ref payloadKind);
 
@@ -201,7 +202,7 @@ public static ODataMaterializer CreateMaterializerForMessage(
 
             try
             {
-                ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, annotationsCache);
+                ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, materializerCache);
 
                 // Since in V1/V2, astoria client allowed Execute<object> and depended on the typeresolver or the wire type name
                 // to get the clr type to materialize. Hence if we see the materializer type as object, we should set the edmtype
diff --git a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
index 923a221257..bf8b0ca290 100644
--- a/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/ODataMaterializerContext.cs
@@ -19,10 +19,11 @@ internal class ODataMaterializerContext : IODataMaterializerContext
         /// Initializes a materializer context
         /// </summary>
         /// <param name="responseInfo">Response information used to initialize with the materializer</param>
-        internal ODataMaterializerContext(ResponseInfo responseInfo, MaterializerAnnotationsCache annotationsCache)
+        /// <param name="materializerCache">The materializer cache.</param>
+        internal ODataMaterializerContext(ResponseInfo responseInfo, MaterializerCache materializerCache)
         {
             this.ResponseInfo = responseInfo;
-            this.AnnotationsCache = annotationsCache;
+            this.MaterializerCache = materializerCache;
         }
 
         /// <summary>
@@ -86,6 +87,7 @@ public IEdmType ResolveExpectedTypeForReading(Type expectedType)
             return this.ResponseInfo.TypeResolver.ResolveExpectedTypeForReading(expectedType);
         }
 
-        public MaterializerAnnotationsCache AnnotationsCache { get; private set; }
+        /// <inheritdoc/>
+        public MaterializerCache MaterializerCache { get; private set; }
     }
 }
diff --git a/src/Microsoft.OData.Client/MaterializeFromAtom.cs b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
index aff289e1d3..80b057e17b 100644
--- a/src/Microsoft.OData.Client/MaterializeFromAtom.cs
+++ b/src/Microsoft.OData.Client/MaterializeFromAtom.cs
@@ -74,14 +74,14 @@ internal class MaterializeAtom : IDisposable, IEnumerable, IEnumerator
         /// <param name="plan">Projection plan (if compiled in an earlier query).</param>
         /// <param name="responseMessage">responseMessage</param>
         /// <param name="payloadKind">The kind of the payload to materialize.</param>
-        /// <param name="annotationsCache">The annotations cache used to store and retrieve temporary metadata used for materialization of OData items.</param>
+        /// <param name="materializerCache">Cache used to store temporary metadata used for materialization of OData items.</param>
         internal MaterializeAtom(
             ResponseInfo responseInfo,
             QueryComponents queryComponents,
             ProjectionPlan plan,
             IODataResponseMessage responseMessage,
             ODataPayloadKind payloadKind,
-            MaterializerAnnotationsCache annotationsCache)
+            MaterializerCache materializerCache)
         {
             Debug.Assert(queryComponents != null, "queryComponents != null");
 
@@ -93,7 +93,7 @@ internal MaterializeAtom(
 
             Type implementationType;
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
-            this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind, annotationsCache);
+            this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind, materializerCache);
         }
 
         /// <summary>
@@ -103,8 +103,8 @@ internal MaterializeAtom(
         /// <param name="entries">entries that needs to be materialized.</param>
         /// <param name="elementType">result type.</param>
         /// <param name="format">The format of the response being materialized from.</param>
-        /// <param name="annotationsCache">The annotations cache used to store and retrieve temporary metadata used for materialization of OData items.</param>
-        internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> entries, Type elementType, ODataFormat format, MaterializerAnnotationsCache annotationsCache)
+        /// <param name="materializerCache">Cache used to store temporary metadata used for materialization of OData items.</param>
+        internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> entries, Type elementType, ODataFormat format, MaterializerCache materializerCache)
         {
             this.responseInfo = responseInfo;
             this.elementType = elementType;
@@ -113,7 +113,7 @@ internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable<ODataResource> e
             Type implementationType;
             Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);
             QueryComponents qc = new QueryComponents(null, Util.ODataVersionEmpty, elementType, null, null);
-            ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, annotationsCache);
+            ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, materializerCache);
             EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context, materializerContext);
             this.materializer = new ODataEntriesEntityMaterializer(entries, materializerContext, entityTrackingAdapter, qc, materializerType, null, format);
         }
diff --git a/src/Microsoft.OData.Client/QueryResult.cs b/src/Microsoft.OData.Client/QueryResult.cs
index 812da403b0..eb0d6a7ed0 100644
--- a/src/Microsoft.OData.Client/QueryResult.cs
+++ b/src/Microsoft.OData.Client/QueryResult.cs
@@ -708,7 +708,7 @@ private MaterializeAtom CreateMaterializer(ProjectionPlan plan, ODataPayloadKind
                 this.ContentType,
                 responseMessageWrapper,
                 payloadKind,
-                this.annotationsCache);
+                this.materializerCache);
         }
     }
 }
diff --git a/src/Microsoft.OData.Client/SaveResult.cs b/src/Microsoft.OData.Client/SaveResult.cs
index 80ce34218f..a3c14f7165 100644
--- a/src/Microsoft.OData.Client/SaveResult.cs
+++ b/src/Microsoft.OData.Client/SaveResult.cs
@@ -360,7 +360,7 @@ protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescri
         {
             Debug.Assert(this.cachedResponse.Exception == null && this.cachedResponse.MaterializerEntry != null, "this.cachedResponse.Exception == null && this.cachedResponse.Entry != null");
             ODataResource entry = this.cachedResponse.MaterializerEntry == null ? null : this.cachedResponse.MaterializerEntry.Entry;
-            return new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format, annotationsCache);
+            return new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format, this.materializerCache);
         }
 
         /// <summary>
@@ -865,7 +865,7 @@ private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stre
                             responseMsg.StatusCode,
                             () => responseStream);
 
-                        ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, this.annotationsCache);
+                        ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo, this.materializerCache);
                         entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType(), materializerContext);
                         entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor;
                     }
diff --git a/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs b/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
index 9dc9718aad..12cf8e1486 100644
--- a/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
+++ b/test/FunctionalTests/Microsoft.OData.Client.Tests/Tracking/DataServiceContextNoTrackingStreamsTests.cs
@@ -234,7 +234,7 @@ public void TestAddingNewItemsBehaviourShouldBeUnAltered()
             Assert.NotNull(NonTrackingContext.GetEntityDescriptor(user));
             Assert.NotNull(DefaultTrackingContext.GetEntityDescriptor(user));
 
-            SaveContextChanges(new DataServiceContext[] { DefaultTrackingContext });//, NonTrackingContext });
+            SaveContextChanges(new DataServiceContext[] { DefaultTrackingContext, NonTrackingContext });
             Assert.Single(DefaultTrackingContext.Entities);
             Assert.Single(NonTrackingContext.Entities);
         }
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
index 07fd87e2ee..27edd8fd1c 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/DataServiceRequestTests.cs
@@ -59,7 +59,7 @@ private void MaterializeTest(HttpStatusCode statusCode, ODataPayloadKind payload
                 new HeaderCollection(),
                 (int)statusCode,
                 () => new MemoryStream());
-            var annotationsCache = new MaterializerAnnotationsCache();
+            var materializerCache = new MaterializerCache();
             var materialize = DataServiceRequest.Materialize(
                 responseInfo,
                 queryComponents,
@@ -67,7 +67,7 @@ private void MaterializeTest(HttpStatusCode statusCode, ODataPayloadKind payload
                 "application/json",
                 responseMessage,
                 payloadKind,
-                annotationsCache);
+                materializerCache);
             Assert.Null(materialize.Context);
             Assert.Null(materialize.Current);
             var enumerable = materialize.Cast<object>();
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
index e0e3c7fdb9..03539d18cc 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/CollectionValueMaterializationPolicyTests.cs
@@ -130,7 +130,7 @@ public void AddingCollectionToComplexCollectionShouldFail()
         [Fact]
         public void DataServicCollectionOfTAsCollectionTypeShouldFailForPrimitiveOrComplexCollections()
         {
-            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var testContext = new TestMaterializerContext(new MaterializerCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(MyInfo));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(MyInfo), "MyInfo", testContext.Model);
 
@@ -141,7 +141,7 @@ public void DataServicCollectionOfTAsCollectionTypeShouldFailForPrimitiveOrCompl
         [Fact]
         public void CreateCollectionInstanceShouldFailOnTypeWithNoParametersLessConstructors()
         {
-            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var testContext = new TestMaterializerContext(new MaterializerCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(ListWithNoEmptyConstructors), "Points", testContext.Model);
 
@@ -153,7 +153,7 @@ public void CreateCollectionInstanceShouldFailOnTypeWithNoParametersLessConstruc
         public void CreateCollectionPropertyInstanceShouldFailOnTypeWithNoParametersLessConstructors()
         {
             var odataProperty = new ODataProperty() { Name = "foo", Value = new ODataCollectionValue() { TypeName = "Points" } };
-            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var testContext = new TestMaterializerContext(new MaterializerCache());
             testContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
                 var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
@@ -167,7 +167,7 @@ public void CreateCollectionPropertyInstanceShouldFailOnTypeWithNoParametersLess
         [Fact]
         public void NonMissingMethodExceptionOnCreateInstanceShouldNotBeCaught()
         {
-            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var testContext = new TestMaterializerContext(new MaterializerCache());
             var edmType = testContext.Model.GetOrCreateEdmType(typeof(ListWithNoEmptyConstructors));
             var clientTypeAnnotation = new ClientTypeAnnotation(edmType, typeof(ErrorThrowingList), "Points", testContext.Model);
 
@@ -181,7 +181,7 @@ public void NonMissingMethodExceptionOnCreateInstanceShouldNotBeCaught()
 
         internal CollectionValueMaterializationPolicy CreateCollectionValueMaterializationPolicy()
         {
-            return CreateCollectionValueMaterializationPolicy(new TestMaterializerContext(new MaterializerAnnotationsCache()));
+            return CreateCollectionValueMaterializationPolicy(new TestMaterializerContext(new MaterializerCache()));
         }
 
         internal CollectionValueMaterializationPolicy CreateCollectionValueMaterializationPolicy(IODataMaterializerContext materializerContext)
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
index 3ab8301b14..c8a45c571b 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryMaterializationPolicyForComplexResourceTests.cs
@@ -50,7 +50,7 @@ public void ComplexWithPrimitiveValueShouldMaterialize()
         [Fact]
         public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache()) { UndeclaredPropertyBehavior = DSClient.UndeclaredPropertyBehavior.Support };
             CollectionValueMaterializationPolicyTests.Point point = new CollectionValueMaterializationPolicyTests.Point();
             ODataProperty property = new ODataProperty() { Name = "Z", Value = 10 };
             this.CreateEntryMaterializationPolicy(materializerContext)
@@ -60,7 +60,7 @@ public void ApplyNonExistantPropertyWithIgnoreMissingPropertiesShouldNotError()
         [Fact]
         public void ApplyNullOnCollectionPropertyShouldError()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = null };
 
@@ -71,7 +71,7 @@ public void ApplyNullOnCollectionPropertyShouldError()
         [Fact]
         public void ApplyStringValueForCollectionPropertyShouldError()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = "foo" };
 
@@ -82,8 +82,8 @@ public void ApplyStringValueForCollectionPropertyShouldError()
         [Fact]
         public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         {
-            var annotationsCache = new MaterializerAnnotationsCache();
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(annotationsCache);
+            var materializerCache = new MaterializerCache();
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(materializerCache);
 
             //In a true client, a TypeResolver will be used to resolve derived property type.
             materializerContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
@@ -110,7 +110,7 @@ public void MaterializeDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyDerivedComplexForBaseComplexTypeProperty()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
 
             materializerContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
@@ -141,7 +141,7 @@ public void ApplyDerivedComplexForBaseComplexTypeProperty()
         [Fact]
         public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
 
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings.Add("ShouldBeCleared");
@@ -157,7 +157,7 @@ public void ApplyODataCollectionValueToNonNullExistingCollectionProperty()
         [Fact]
         public void ApplyODataCollectionValueToNullCollectionProperty()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
             ComplexTypeWithPrimitiveCollection complexInstance = new ComplexTypeWithPrimitiveCollection();
             complexInstance.Strings = null;
             ODataProperty property = new ODataProperty() { Name = "Strings", Value = new ODataCollectionValue() { Items = new string[] { "foo" }, TypeName = typeof(ComplexTypeWithPrimitiveCollection).FullName } };
@@ -172,7 +172,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         {
             foreach (var startingPropertyState in new ChildComplexType[] { null, new ChildComplexType() })
             {
-                TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+                TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
                 ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
                 complexInstance.InnerComplexProperty = startingPropertyState;
                 var innerEntry = new ODataResource() { Properties = new ODataProperty[] { new ODataProperty() { Name = "Prop", Value = 1 } } };
@@ -184,7 +184,7 @@ public void ValueShouldBeAppliedRegardlessIfPropertyStartsNullOrNot()
         [Fact]
         public void NullValueShouldBeAppliedToSubComplexValueProperty()
         {
-            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            TestMaterializerContext  materializerContext = new TestMaterializerContext(new MaterializerCache());
             ComplexTypeWithChildComplexType complexInstance = new ComplexTypeWithChildComplexType();
             complexInstance.InnerComplexProperty = new ChildComplexType();
 
@@ -194,7 +194,7 @@ public void NullValueShouldBeAppliedToSubComplexValueProperty()
 
         private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext  materializerContext = null)
         {
-            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache());
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerCache());
             var resource = new ODataResource() { TypeName = "ComplexTypeWithChildComplexType", Properties = new ODataProperty[0] };
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
@@ -224,7 +224,7 @@ internal EntryValueMaterializationPolicy CreateEntryMaterializationPolicy(TestMa
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerCache()) { Model = clientEdmModel, Context = context };
             var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             var lazyPrimitivePropertyConverter = new DSClient.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter());
             var primitiveValueMaterializerPolicy = new PrimitiveValueMaterializationPolicy(materializerContext, lazyPrimitivePropertyConverter);
@@ -274,7 +274,7 @@ public void ShouldMaterializeConcreteComplexCollectionDeclaredAsAbstract()
                 new ODataResource(){Properties = new ODataProperty[]{ new ODataProperty(){Name="Points", Value = 0}, new ODataProperty(){Name="Diameter", Value = 18} }},
             });
 
-            var testContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var testContext = new TestMaterializerContext(new MaterializerCache());
             testContext.ResolveTypeForMaterializationOverrideFunc = (Type type, string name) =>
             {
                 var edmType = testContext.Model.GetOrCreateEdmType(typeof(CollectionValueMaterializationPolicyTests.Circle));
@@ -328,7 +328,7 @@ internal ODataEntriesEntityMaterializer CreateODataEntriesEntityMaterializer(
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerCache()) { Model = clientEdmModel, Context = context };
 
             var resourceSet = new ODataResourceSet();
             MaterializerFeed.CreateFeed(resourceSet, resources, materializerContext);
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
index fa5ae38c07..d8e7ed2303 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/EntryValueMaterializationPolicyUnitTests.cs
@@ -41,7 +41,7 @@ public EntryValueMaterializationPolicyUnitTests()
             this.clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             this.clientEdmModel.GetOrCreateEdmType(typeof(TestCustomer));
             this.clientEdmModel.GetOrCreateEdmType(typeof(TestOrder));
-            this.materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = this.clientEdmModel };
+            this.materializerContext = new TestMaterializerContext(new MaterializerCache()) { Model = this.clientEdmModel };
             this.ordersProperty = this.clientEdmModel.GetClientTypeAnnotation(typeof(TestCustomer)).GetProperty("Orders", UndeclaredPropertyBehavior.ThrowException);
         }
 
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
index 09a01fa39a..e9805920b9 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/FeedAndEntryMaterializerAdapterUnitTests.cs
@@ -52,7 +52,7 @@ public void ValidateShortIntegrationFeedReading()
 
             var responsePipeline = new DataServiceClientResponsePipelineConfiguration(new DataServiceContext());
             var odataReaderWrapper = ODataReaderWrapper.CreateForTest(testODataReader, responsePipeline);
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerContext = new TestMaterializerContext(new MaterializerCache());
             FeedAndEntryMaterializerAdapter reader = new FeedAndEntryMaterializerAdapter(ODataFormat.Json, odataReaderWrapper, clientEdmModel, MergeOption.OverwriteChanges, materializerContext);
 
             int readCounter = 0;
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
index 8a455e455b..ab815f798b 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/MaterializerEntryTests.cs
@@ -64,7 +64,7 @@ private MaterializerEntry CreateMaterializerEntry(ODataFormat format, Action<ODa
                 modifyEntry(entry);
             }
 
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerContext = new TestMaterializerContext(new MaterializerCache());
             return MaterializerEntry.CreateEntry(entry, format, true, this.clientModel, materializerContext);
         }
     }
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
index 23d771e718..de1b7611ab 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntityMaterializerUnitTests.cs
@@ -31,7 +31,7 @@ public ODataEntityMaterializerUnitTests()
         [Fact]
         public void AfterEntryMaterializedShouldOccur()
         {
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerContext = new TestMaterializerContext(new MaterializerCache());
 
             foreach (ODataFormat format in new ODataFormat[] { ODataFormat.Json })
             {
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
index 0b7550541b..69f3aefa88 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/ODataEntriesEntityMaterializerUnitTests.cs
@@ -30,7 +30,7 @@ public void ShortIntegrationTestToValidateEntryShouldBeRead()
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            var materializerContext = new TestMaterializerContext(new MaterializerCache()) { Model = clientEdmModel, Context = context };
             MaterializerEntry.CreateEntry(odataEntry, ODataFormat.Json, true, clientEdmModel, materializerContext);
             
             var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
index 2da7be54a6..1d35ad1840 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/PrimitiveValueMaterializationPolicyTests.cs
@@ -63,7 +63,7 @@ public void TimeOfDayValueShouldMaterializeCorrectly()
 
         internal PrimitiveValueMaterializationPolicy CreatePrimitiveValueMaterializationPolicy()
         {
-            return new PrimitiveValueMaterializationPolicy(new TestMaterializerContext(new MaterializerAnnotationsCache()), new SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter()));
+            return new PrimitiveValueMaterializationPolicy(new TestMaterializerContext(new MaterializerCache()), new SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter()));
         }
 
         public class UnknownPoint
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
index 67bbf93737..246919b7c8 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/Materialization/TestMaterializerContext.cs
@@ -17,13 +17,13 @@ namespace AstoriaUnitTests.Tests
     /// </summary>
     internal class TestMaterializerContext : IODataMaterializerContext
     {
-        public TestMaterializerContext(MaterializerAnnotationsCache annotationsCache)
+        public TestMaterializerContext(MaterializerCache materializerCache)
         {
             this.UndeclaredPropertyBehavior = UndeclaredPropertyBehavior.ThrowException;
             this.ResponsePipeline = new DataServiceClientResponsePipelineConfiguration(this);
             this.Model = new ClientEdmModel(ODataProtocolVersion.V4);
             this.Context = new DataServiceContext();
-            this.AnnotationsCache = annotationsCache;
+            this.MaterializerCache = materializerCache;
         }
 
         public Func<Type, string, ClientTypeAnnotation> ResolveTypeForMaterializationOverrideFunc { get; set; }
@@ -52,6 +52,6 @@ public IEdmType ResolveExpectedTypeForReading(Type expectedType)
 
         public DataServiceContext Context { get; set; }
 
-        public MaterializerAnnotationsCache AnnotationsCache { get; private set; }
+        public MaterializerCache MaterializerCache { get; private set; }
     }
 }
diff --git a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
index 3a7546d2d9..e24036be19 100644
--- a/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
+++ b/test/FunctionalTests/Tests/DataServices/UnitTests/Client.TDD.Tests/Tests/T4/ODataT4CamelCaseTests.cs
@@ -322,7 +322,7 @@ public void MaterializeEntityShouldWork()
 
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext();
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            var materializerContext = new TestMaterializerContext(new MaterializerCache()) { Model = clientEdmModel, Context = context };
             var materializerEntry = MaterializerEntry.CreateEntry(odataEntry, OData.ODataFormat.Json, true, clientEdmModel, materializerContext);
 
             MaterializerNavigationLink.CreateLink(complexP, MaterializerEntry.CreateEntry(complexResource, OData.ODataFormat.Json, true, clientEdmModel, materializerContext), materializerContext);
@@ -382,7 +382,7 @@ public void MaterializeComplexTypeShouldWork()
                 }
             };
 
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerContext = new TestMaterializerContext(new MaterializerCache());
             var materializerEntry = MaterializerEntry.CreateEntry(complexValue, OData.ODataFormat.Json, false, new ClientEdmModel(ODataProtocolVersion.V4), materializerContext);
             this.CreateEntryMaterializationPolicy().Materialize(materializerEntry, typeof(ComplexType), false);
             var complex = materializerEntry.ResolvedObject as ComplexType;
@@ -398,7 +398,7 @@ public void MaterializeEnumTypeShouldWork()
         {
             OData.ODataEnumValue enumValue = new OData.ODataEnumValue("blue");
             OData.ODataProperty property = new OData.ODataProperty { Name = "enumProperty", Value = enumValue };
-            var materializerContext = new TestMaterializerContext(new MaterializerAnnotationsCache());
+            var materializerContext = new TestMaterializerContext(new MaterializerCache());
             var enumPolicy = new EnumValueMaterializationPolicy(materializerContext);
             var result = enumPolicy.MaterializeEnumTypeProperty(typeof(Color), property);
             property.GetMaterializedValue(materializerContext).Should().Be(Color.Blue);
@@ -473,7 +473,7 @@ internal EntryValueMaterializationPolicy CreateEntryMaterializationPolicy(TestMa
         {
             var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
             var context = new DataServiceContext().ReConfigureForNetworkLoadingTests();
-            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerAnnotationsCache()) { Model = clientEdmModel, Context = context };
+            materializerContext = materializerContext ?? new TestMaterializerContext(new MaterializerCache()) { Model = clientEdmModel, Context = context };
             var adapter = new EntityTrackingAdapter(new TestEntityTracker(), MergeOption.OverwriteChanges, clientEdmModel, context, materializerContext);
             var lazyPrimitivePropertyConverter = new Microsoft.OData.Client.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter());
             var primitiveValueMaterializerPolicy = new PrimitiveValueMaterializationPolicy(materializerContext, lazyPrimitivePropertyConverter);

From 310e03b533913b19ad3fa7dfd879300edd017c72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= <haby_habbes@live.com>
Date: Mon, 19 Sep 2022 10:47:21 +0300
Subject: [PATCH 16/16] Update
 src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs

Co-authored-by: Kennedy Kang'ethe <kemunga@microsoft.com>
---
 .../Materialization/IODataMaterializerContext.cs               | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
index 9f435bce90..a1baef5838 100644
--- a/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
+++ b/src/Microsoft.OData.Client/Materialization/IODataMaterializerContext.cs
@@ -54,7 +54,8 @@ internal interface IODataMaterializerContext
         IEdmType ResolveExpectedTypeForReading(Type clientClrType);
 
         /// <summary>
-        /// Used to store temporary metadata used to converter deserialized
+        /// Used to store temporary metadata used to convert deserialized
+
         /// OData items into CLR objects.
         /// </summary>
         MaterializerCache MaterializerCache { get; }