/// <summary>Materializes the specified <paramref name="entry"/> as dynamic property.</summary> /// <param name="entry">Entry with object to materialize.</param> /// <param name="link">Nested resource link as parsed.</param> private void MaterializeDynamicProperty(MaterializerEntry entry, ODataNestedResourceInfo link) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise not resolved/created!"); Debug.Assert(link != null, "link != null"); ClientEdmModel model = this.MaterializerContext.Model; IDictionary <string, object> containerProperty; // Stop if owning type is not an open type // Or container property is not found // Or key with matching name already exists in the dictionary if (!ClientTypeUtil.IsInstanceOfOpenType(entry.ResolvedObject, model) || !ClientTypeUtil.TryGetContainerProperty(entry.ResolvedObject, out containerProperty) || containerProperty.ContainsKey(link.Name)) { return; } MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link); if (linkState == null || (linkState.Entry == null && linkState.Feed == null)) { return; } // NOTE: ODL (and OData WebApi) support navigational property on complex types // That support has not yet been implemented in OData client // An entity or entity collection as a dynamic property currently doesn't work as expected // due to the absence of a navigational property definition in the metadata // to express the relationship between that entity and the parent entity - unless they're the same type! // Only materialize a nested resource if its a complex or complex collection if (linkState.Feed != null) { string collectionTypeName = linkState.Feed.TypeName; // TypeName represents a collection e.g. Collection(NS.Type) string collectionItemTypeName = CommonUtil.GetCollectionItemTypeName(collectionTypeName, false); // Highly unlikely, but the method return null if the typeName argument does not meet certain expectations if (collectionItemTypeName == null) { return; } Type collectionItemType = ResolveClientTypeForDynamicProperty(collectionItemTypeName, entry.ResolvedObject); if (collectionItemType != null && ClientTypeUtil.TypeIsComplex(collectionItemType, model)) { Type collectionType = typeof(System.Collections.ObjectModel.Collection <>).MakeGenericType(new Type[] { collectionItemType }); IList collection = (IList)Util.ActivatorCreateInstance(collectionType); IEnumerable <ODataResource> feedEntries = MaterializerFeed.GetFeed(linkState.Feed).Entries; foreach (ODataResource feedEntry in feedEntries) { MaterializerEntry linkEntry = MaterializerEntry.GetEntry(feedEntry); this.Materialize(linkEntry, collectionItemType, false /*includeLinks*/); collection.Add(linkEntry.ResolvedObject); } containerProperty.Add(link.Name, collection); } } else { MaterializerEntry linkEntry = linkState.Entry; Type itemType = ResolveClientTypeForDynamicProperty(linkEntry.Entry.TypeName, entry.ResolvedObject); if (itemType != null && ClientTypeUtil.TypeIsComplex(itemType, model)) { this.Materialize(linkEntry, itemType, false /*includeLinks*/); containerProperty.Add(link.Name, linkEntry.ResolvedObject); } } }
/// <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) { Debug.Assert(entry.GetType() == typeof(ODataEntry), "entry.GetType() == typeof(ODataEntry)"); return(ODataEntityMaterializer.ProjectionGetEntry(MaterializerEntry.GetEntry((ODataEntry)entry), name)); }
/// <summary>Materializes an entry without including in-lined expanded links.</summary> /// <param name="materializer">Materializer under which materialization should take place.</param> /// <param name="entry">Entry with object to materialize.</param> /// <param name="expectedEntryType">Expected type for the entry.</param> /// <returns>The materialized instance.</returns> internal static object ShallowMaterializePlan(object materializer, object entry, Type expectedEntryType) { Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())"); Debug.Assert(entry.GetType() == typeof(ODataEntry), "entry.GetType() == typeof(ODataEntry)"); return(ODataEntityMaterializer.ShallowMaterializePlan((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataEntry)entry), expectedEntryType)); }
/// <summary>Provides support for Select invocations for projections.</summary> /// <param name="materializer">Materializer under which projection is taking place.</param> /// <param name="entry">Root entry for paths.</param> /// <param name="expectedType">Expected type for <paramref name="entry"/>.</param> /// <param name="resultType">Expected result type.</param> /// <param name="path">Path to traverse.</param> /// <param name="selector">Selector callback.</param> /// <returns>An enumerable with the select results.</returns> internal static IEnumerable ProjectionSelect( object materializer, object entry, Type expectedType, Type resultType, object path, Func <object, object, Type, object> selector) { Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())"); Debug.Assert(entry.GetType() == typeof(ODataEntry), "entry.GetType() == typeof(ODataEntry)"); Debug.Assert(path.GetType() == typeof(ProjectionPath), "path.GetType() == typeof(ProjectionPath)"); return(ODataEntityMaterializer.ProjectionSelect((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataEntry)entry), expectedType, resultType, (ProjectionPath)path, selector)); }
/// <summary>Initializes a projection-driven entry (with a specific type and specific properties).</summary> /// <param name="materializer">Materializer under which projection is taking place.</param> /// <param name="entry">Root entry for paths.</param> /// <param name="expectedType">Expected type for <paramref name="entry"/>.</param> /// <param name="resultType">Expected result type.</param> /// <param name="properties">Properties to materialize.</param> /// <param name="propertyValues">Functions to get values for functions.</param> /// <returns>The initialized entry.</returns> internal static object ProjectionInitializeEntity( object materializer, object entry, Type expectedType, Type resultType, string[] properties, Func <object, object, Type, object>[] propertyValues) { Debug.Assert(typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType()), "typeof(ODataEntityMaterializer).IsAssignableFrom(materializer.GetType())"); Debug.Assert(entry.GetType() == typeof(ODataEntry), "entry.GetType() == typeof(ODataEntry)"); return(ODataEntityMaterializer.ProjectionInitializeEntity((ODataEntityMaterializer)materializer, MaterializerEntry.GetEntry((ODataEntry)entry), expectedType, resultType, properties, propertyValues)); }