internal ClientTypeAnnotation(IEdmType edmType, Type type, string qualifiedName, ClientEdmModel model) { Debug.Assert(edmType != null, "edmType != null"); Debug.Assert(null != type, "null type"); Debug.Assert(!string.IsNullOrEmpty(qualifiedName), "!string.IsNullOrEmpty(qualifiedName)"); this.EdmType = edmType; this.EdmTypeReference = this.EdmType.ToEdmTypeReference(Util.IsNullableType(type)); this.ElementTypeName = qualifiedName; this.ElementType = Nullable.GetUnderlyingType(type) ?? type; this.model = model; }
public ClientEdmStructuredValueTests() { this._address = new Address { Street = "123 fake st" }; this._entity = new Customer { Id = 1, Address = this._address, Emails = new List <string> { "*****@*****.**" } }; var model = new ClientEdmModel(ODataProtocolVersion.V4); var entityType = model.GetOrCreateEdmType(typeof(Customer)); var complexType = model.GetOrCreateEdmType(typeof(Address)); this._complexValue = new ClientEdmStructuredValue(this._address, model, model.GetClientTypeAnnotation(complexType)); this._entityValue = new ClientEdmStructuredValue(this._entity, model, model.GetClientTypeAnnotation(entityType)); }
public void DeclaringTypeOFAnEntityNavigationCanBeAComplexType() { //Arrange Type complexDeclaringType = typeof(Address); Type entityNavigationType = typeof(City); EdmTypeKind expectedDeclaringTypeKind = EdmTypeKind.Complex; //Act ClientEdmModel clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V401); IEdmType edmTypeOfComplexDeclaringType = clientEdmModel.GetOrCreateEdmType(complexDeclaringType); IEdmType edmTypeOfEntityNavigationType = clientEdmModel.GetOrCreateEdmType(entityNavigationType); IEdmStructuredType entiyNavigationType = clientEdmModel.GetOrCreateEdmType(complexDeclaringType) as IEdmStructuredType; EdmNavigationProperty edmNavigationProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner("City", ClientTypeUtil.ToEdmTypeReference(edmTypeOfEntityNavigationType, true), null, null, false, EdmOnDeleteAction.None, "Partner", ClientTypeUtil.ToEdmTypeReference(edmTypeOfComplexDeclaringType, true), null, null, false, EdmOnDeleteAction.None); EdmTypeKind resultingDeclaringTypeKind = edmNavigationProperty.DeclaringType.TypeKind; //Assert Assert.Equal(expectedDeclaringTypeKind, resultingDeclaringTypeKind); }
/// <summary> /// Get or create a client EDM type instance. /// </summary> /// <param name="type">type to wrap</param> /// <returns>client type</returns> internal IEdmType GetOrCreateEdmType(Type type) { Debug.Assert(type != null, "type != null"); EdmTypeCacheValue cachedEdmType; lock (this.clrToEdmTypeCache) { this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType); } if (cachedEdmType == null) { if (PrimitiveType.IsKnownNullableType(type)) { cachedEdmType = this.GetOrCreateEdmTypeInternal(null /*baseType*/, type, ClientTypeUtil.EmptyPropertyInfoArray, false /*isEntity*/, false /*hasProperties*/); } else { PropertyInfo[] keyProperties; bool hasProperties; Type[] hierarchy = ClientEdmModel.GetTypeHierarchy(type, out keyProperties, out hasProperties); Debug.Assert(keyProperties == null || keyProperties.Length == 0 || keyProperties.All(p => p.DeclaringType == keyProperties[0].DeclaringType), "All key properties must be declared on the same type."); bool isEntity = keyProperties != null; keyProperties = keyProperties ?? ClientTypeUtil.EmptyPropertyInfoArray; foreach (Type t in hierarchy) { // Pass in the full list of key properties for the most base type to be added there. We only allow key properties to be // declared on the same type. IEdmStructuredType edmBaseType = cachedEdmType == null ? null : cachedEdmType.EdmType as IEdmStructuredType; cachedEdmType = this.GetOrCreateEdmTypeInternal(edmBaseType, t, keyProperties, isEntity, t == type ? hasProperties : (bool?)null); // Pass in an empty PropertyInfo array on subsequent derived types. keyProperties = ClientTypeUtil.EmptyPropertyInfoArray; } } } Debug.Assert(cachedEdmType != null, "cachedEdmType != null"); this.ValidateComplexType(type, cachedEdmType); return(cachedEdmType.EdmType); }
/// <summary> /// Reads from message reader. /// </summary> /// <param name="expectedClientType">The expected client type being materialized into.</param> /// <param name="expectedReaderType">The expected type for the underlying reader.</param> protected override void ReadWithExpectedType(IEdmTypeReference expectedClientType, IEdmTypeReference expectedReaderType) { this.ReadLinks(); Type underlyingExpectedType = Nullable.GetUnderlyingType(this.ExpectedType) ?? this.ExpectedType; ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation targetType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(underlyingExpectedType)); // If the target type is an entity, then we should throw since the type on the wire was not an entity if (targetType.IsEntityType) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidEntityType(targetType.ElementTypeName)); } else { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment); } }
/// <summary> /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity). /// </summary> /// <param name="type">Type being checked.</param> /// <param name="model">The client model.</param> /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns> internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model) { // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us. if (!PrimitiveType.IsKnownNullableType(type)) { Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if (collectionType != null) { // collectionType is ICollection so we know that the first generic parameter // is the collection item type if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model)) { return(true); } } } return(false); }
internal EntryValueMaterializationPolicy CreateEntryMaterializationPolicy(TestMaterializerContext materializerContext = null) { 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); var lazyPrimitivePropertyConverter = new Microsoft.OData.Client.SimpleLazy <PrimitivePropertyConverter>(() => new PrimitivePropertyConverter()); var primitiveValueMaterializerPolicy = new PrimitiveValueMaterializationPolicy(materializerContext, lazyPrimitivePropertyConverter); var entryPolicy = new EntryValueMaterializationPolicy(materializerContext, adapter, lazyPrimitivePropertyConverter, null); var collectionPolicy = new CollectionValueMaterializationPolicy(materializerContext, primitiveValueMaterializerPolicy); var intanceAnnotationPolicy = new InstanceAnnotationMaterializationPolicy(materializerContext); entryPolicy.CollectionValueMaterializationPolicy = collectionPolicy; entryPolicy.InstanceAnnotationMaterializationPolicy = intanceAnnotationPolicy; return(entryPolicy); }
private static ODataResource CreateODataEntry <T>(Action <EntityDescriptor> configureDescriptor = null, Action <DataServiceClientFormat> configureFormat = null, string serverTypeName = "serverTypeName", string clientTypeName = "clientTypeName") { ClientEdmModel model = new ClientEdmModel(ODataProtocolVersion.V4); var ctx = new DataServiceContext(new Uri("http://www.example.com/odata.svc"), ODataProtocolVersion.V4, model); EntityDescriptor entityDescriptor = new EntityDescriptor(model); if (configureDescriptor != null) { configureDescriptor(entityDescriptor); } if (configureFormat != null) { configureFormat(ctx.Format); } ClientTypeAnnotation clientTypeAnnotation = new ClientTypeAnnotation(new EdmEntityType("Fake", "Fake"), typeof(T), clientTypeName, model); return(Serializer.CreateODataEntry(entityDescriptor, serverTypeName, clientTypeAnnotation, ctx.Format)); }
public void ShortIntegrationTestToValidateEntryShouldBeRead() { var odataEntry = new ODataResource() { Id = new Uri("http://services.odata.org/OData/OData.svc/Customers(0)") }; odataEntry.Properties = new ODataProperty[] { new ODataProperty() { Name = "ID", Value = 0 }, new ODataProperty() { Name = "Description", Value = "Simple Stuff" } }; 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); 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); var customersRead = new List <Customer>(); // This line will call ODataEntityMaterializer.ReadImplementation() which will reconstruct the entity, and will get non-public setter called. while (entriesMaterializer.Read()) { customersRead.Add(entriesMaterializer.CurrentValue as Customer); } customersRead.Should().HaveCount(1); customersRead[0].ID.Should().Be(0); customersRead[0].Description.Should().Be("Simple Stuff"); }
protected static void ApplyCollectionDataValues(ODataProperty collectionProperty, bool ignoreMissingProperties, System.Data.Services.Client.ResponseInfo responseInfo, object collectionInstance, Type collectionItemType, Action <object, object> AddValueToBackingICollectionInstance) { ODataCollectionValue value2 = collectionProperty.Value as ODataCollectionValue; if (value2.Items != null) { bool flag = PrimitiveType.IsKnownNullableType(collectionItemType); ClientEdmModel model = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion); foreach (object obj2 in value2.Items) { if (obj2 == null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_NullCollectionItemsNotSupported); } if (flag) { object obj3; if ((obj2 is ODataComplexValue) || (obj2 is ODataCollectionValue)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } MaterializePrimitiveDataValue(collectionItemType, value2.TypeName, obj2, responseInfo, () => System.Data.Services.Client.Strings.Collection_NullCollectionItemsNotSupported, out obj3); AddValueToBackingICollectionInstance(collectionInstance, ConvertPrimitiveValue(obj2, collectionItemType)); } else { ODataComplexValue value3 = obj2 as ODataComplexValue; if (value3 == null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(collectionItemType)); object instance = clientTypeAnnotation.CreateInstance(); ApplyDataValues(clientTypeAnnotation, value3.Properties, ignoreMissingProperties, responseInfo, instance); AddValueToBackingICollectionInstance(collectionInstance, instance); } } } collectionProperty.SetMaterializedValue(collectionInstance); }
private bool TryResolveFromContext(MaterializerEntry entry, Type expectedEntryType) { if (this.mergeOption != MergeOption.NoTracking) { EntityStates states; entry.ResolvedObject = base.ResponseInfo.EntityTracker.TryGetEntity(entry.Id, out states); if (entry.ResolvedObject != null) { if (!expectedEntryType.IsInstanceOfType(entry.ResolvedObject)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_Current(expectedEntryType, entry.ResolvedObject.GetType())); } ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); entry.ActualType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entry.ResolvedObject.GetType())); entry.EntityHasBeenResolved = true; entry.ShouldUpdateFromPayload = ((this.mergeOption == MergeOption.OverwriteChanges) || ((this.mergeOption == MergeOption.PreserveChanges) && (states == EntityStates.Unchanged))) || ((this.mergeOption == MergeOption.PreserveChanges) && (states == EntityStates.Deleted)); this.log.FoundExistingInstance(entry); return(true); } } return(false); }
protected static void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue, bool ignoreMissingProperties, System.Data.Services.Client.ResponseInfo responseInfo) { object instance = null; if ((complexValue != null) && !complexValue.HasMaterializedValue()) { ClientTypeAnnotation actualType = null; if (WebUtil.IsWireTypeCollection(complexValue.TypeName)) { actualType = responseInfo.TypeResolver.ResolveEdmTypeName(propertyType, complexValue.TypeName); } else { ClientEdmModel model = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion); actualType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(propertyType)); } instance = Util.ActivatorCreateInstance(propertyType, new object[0]); MaterializeDataValues(actualType, complexValue.Properties, ignoreMissingProperties); ApplyDataValues(actualType, complexValue.Properties, ignoreMissingProperties, responseInfo, instance); complexValue.SetMaterializedValue(instance); } }
private void InitializeEdmModel() { this.clientModel = new ClientEdmModel(ODataProtocolVersion.V4); this.dataServiceContext = new DataServiceContext(new Uri(ServiceUri), ODataProtocolVersion.V4, this.clientModel); this.dataServiceContext.UndeclaredPropertyBehavior = UndeclaredPropertyBehavior.Support; this.dataServiceContext.ResolveType = (typeName) => { return(this.dataServiceContext.DefaultResolveType(typeName, "NS.Models", "NS.Models")); }; this.dataServiceContext.ResolveName = (clientType) => { var originalNameAttribute = (OriginalNameAttribute)Enumerable.SingleOrDefault(Utility.GetCustomAttributes(clientType, typeof(OriginalNameAttribute), true)); if (clientType.Namespace.Equals("NS.Models", global::System.StringComparison.Ordinal)) { if (originalNameAttribute != null) { return(string.Concat("NS.Models.", originalNameAttribute.OriginalName)); } return(string.Concat("NS.Models.", clientType.Name)); } if (originalNameAttribute != null) { return(clientType.Namespace + "." + originalNameAttribute.OriginalName); } return(clientType.FullName); }; using (var reader = XmlReader.Create(new StringReader(CamelCasedEdmx))) { if (CsdlReader.TryParse(reader, out IEdmModel serviceModel, out _)) { this.dataServiceContext.Format.UseJson(serviceModel); } } }
/// <summary>Materializes a complex type property.</summary> /// <param name="propertyType">Type of the complex type to set.</param> /// <param name="complexValue">The OData complex value.</param> internal void MaterializeComplexTypeProperty(Type propertyType, ODataComplexValue complexValue) { //// TODO: we decide whether the type is primitive or complex only based on the payload. If there is a mismatch we throw a random exception. //// We should have a similar check to the one we have for non-projection codepath here. if (complexValue == null || complexValue.HasMaterializedValue()) { return; } ClientTypeAnnotation complexType = null; // TODO: We should call type resolver for complex types for projections if they are not instantiated by the user directly // with "new" operator. At the moment we don't do it at all. Let's be consistent for Collections and call type // resolver as we do in DirectMaterializationPlan (even though this is only for negative cases for Collections as property.IsCollection // must have been false otherwise we would have not end up here). // This bug is about investigating when we actually do call type resolver and fix it so that we call it when needed and don't // call it when we should not (i.e. it should not be called for types created with "new" operator"). if (!string.IsNullOrEmpty(complexValue.TypeName)) { complexType = this.MaterializerContext.ResolveTypeForMaterialization(propertyType, complexValue.TypeName); } else { ClientEdmModel edmModel = this.MaterializerContext.Model; complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(propertyType)); } object complexInstance = this.CreateNewInstance(complexType.EdmType.ToEdmTypeReference(true), complexType.ElementType); this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties); this.ApplyDataValues(complexType, complexValue.Properties, complexInstance); complexValue.SetMaterializedValue(complexInstance); if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization) { this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance); } }
public TypeResolverTests() { this.serverModel = new EdmModel(); this.clientModel = new ClientEdmModel(ODataProtocolVersion.V4); this.clientEntityType = (IEdmEntityType)this.clientModel.GetOrCreateEdmType(typeof(TestClientEntityType)); this.clientIdProperty = new EdmStructuralProperty(this.clientEntityType, "Id", EdmCoreModel.Instance.GetInt32(false)); var serverType = new EdmEntityType("FQ.NS", "TestServerType"); this.serverModel.AddElement(serverType); var serverContainer = new EdmEntityContainer("FQ.NS", "Container"); this.serverModel.AddElement(serverContainer); serverContainer.AddEntitySet("Entities", serverType); var serverType2 = new EdmEntityType("FQ.NS", "TestServerType2"); this.serverModel.AddElement(serverType2); serverType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { Name = "Navigation", Target = serverType2, TargetMultiplicity = EdmMultiplicity.ZeroOrOne }); }
private void AssertPrimitiveTypeReferenceGeneration(bool makeNullable, string errorMessage) { foreach (var dataServiceProtocolVersion in new[] { ODataProtocolVersion.V4 }) { ClientEdmModel clientEdmModel = new ClientEdmModel(dataServiceProtocolVersion); foreach (var primitivePropertyType in clrTypeToEdmTypeMapping) { Type nullableType = primitivePropertyType.Value; if (makeNullable) { nullableType = typeof(Nullable <>).MakeGenericType(primitivePropertyType.Value); } var primitiveEdmType = clientEdmModel.GetOrCreateEdmType(nullableType) as IEdmPrimitiveType; Assert.Equal("Edm", primitiveEdmType.Namespace); Assert.Equal(GetFullName(primitiveEdmType), primitivePropertyType.Key); Assert.Equal(EdmTypeKind.Primitive, primitiveEdmType.TypeKind); IEdmTypeReference primitiveTypeReference = primitiveEdmType.ToEdmTypeReference(makeNullable); Assert.Equal(primitiveTypeReference.IsNullable, makeNullable); } } }
/// <summary> /// Initializes a new instance of the <see cref="ClientEdmStructuredValue"/> class. /// </summary> /// <param name="structuredValue">The structured value.</param> /// <param name="model">The model.</param> /// <param name="clientTypeAnnotation">The client type annotation.</param> public ClientEdmStructuredValue(object structuredValue, ClientEdmModel model, ClientTypeAnnotation clientTypeAnnotation) { Debug.Assert(structuredValue != null, "entity != null"); Debug.Assert(model != null, "model != null"); Debug.Assert(clientTypeAnnotation != null, "clientTypeAnnotation != null"); if (clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Complex) { // TODO: nullable? this.Type = new EdmComplexTypeReference((IEdmComplexType)clientTypeAnnotation.EdmType, true); } else { Debug.Assert(clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Entity, "Only complex and entity values supported"); // TODO: nullable? this.Type = new EdmEntityTypeReference((IEdmEntityType)clientTypeAnnotation.EdmType, true); } this.structuredValue = structuredValue; this.typeAnnotation = clientTypeAnnotation; this.model = model; }
/// <summary> /// Get the entity set name for the target entity object. /// </summary> /// <param name="target">An entity object.</param> /// <param name="targetEntitySet">The 'currently known' entity set name for the target object.</param> /// <param name="model">The client model.</param> /// <returns>The entity set name for the target object.</returns> /// <remarks> /// Allow user code to provide the entity set name. If user code does not provide the entity set name, then /// this method will get the entity set name from the value of the EntitySetAttribute. /// The 'currently known' entity set name for top level collections can be provided through OEC constructor /// </remarks> internal static string GetEntitySet( object target, string targetEntitySet, ClientEdmModel model) { Debug.Assert(target != null, "Argument 'target' cannot be null."); Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType(), model), "Argument 'target' must be an entity type."); // Here's the rules in order of priority for resolving entity set name // 1. EntitySet name passed in the constructor or extension methods of DataServiceCollection // 2. EntitySet name specified in the EntitySet attribute by the code gen. {Remember this attribute is // not generated in case of MEST) if (!String.IsNullOrEmpty(targetEntitySet)) { return(targetEntitySet); } else { // If there is not a 'currently known' entity set name to validate against, then there must be // EntitySet attribute on the entity type return(BindingEntityInfo.GetEntitySetAttribute(target.GetType(), model)); } }
private void ApplyInnerProperty(ODataResource innerResource, ComplexTypeWithChildComplexType parentInstance, TestMaterializerContext context = null) { context = context ?? new TestMaterializerContext(); 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); materializerEntry.ResolvedObject = parentInstance; ODataNestedResourceInfo innerComplexP = new ODataNestedResourceInfo() { Name = "InnerComplexProperty", IsCollection = false }; MaterializerEntry innerMaterializerEntry; if (innerResource != null) { innerMaterializerEntry = MaterializerEntry.CreateEntry(innerResource, ODataFormat.Json, true, clientEdmModel); } else { innerMaterializerEntry = MaterializerEntry.CreateEmpty(); } MaterializerNavigationLink.CreateLink(innerComplexP, innerMaterializerEntry); materializerEntry.AddNestedResourceInfo(innerComplexP); var policy = this.CreateEntryMaterializationPolicy(context); policy.EntityTrackingAdapter.TargetInstance = parentInstance; policy.Materialize(materializerEntry, typeof(ComplexTypeWithChildComplexType), true); }
/// <summary>Tries to resolve the object as the target one in a POST refresh.</summary> /// <param name="entry">Entry to resolve.</param> /// <returns>true if the entity was resolved; false otherwise.</returns> private bool TryResolveAsTarget(MaterializerEntry entry) { if (entry.ResolvedObject == null) { return(false); } // The only case when the entity hasn't been resolved but // it has already been set is when the target instance // was set directly to refresh a POST. Debug.Assert( entry.ResolvedObject == this.TargetInstance, "entry.ResolvedObject == this.TargetInstance -- otherwise there we ResolveOrCreateInstance more than once on the same entry"); Debug.Assert( this.MergeOption == MergeOption.OverwriteChanges || this.MergeOption == MergeOption.PreserveChanges, "MergeOption.OverwriteChanges and MergeOption.PreserveChanges are the only expected values during SaveChanges"); ClientEdmModel edmModel = this.Model; entry.ActualType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(entry.ResolvedObject.GetType())); this.MaterializationLog.FoundTargetInstance(entry); entry.ShouldUpdateFromPayload = this.MergeOption != MergeOption.PreserveChanges; entry.EntityHasBeenResolved = true; return(true); }
/// <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> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="atomProperty"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="atomProperty">Property as parsed.</param> /// <param name="model">Client model.</param> /// <param name="performEntityCheck">whether to do the entity check or not.</param> internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ClientEdmModel model, bool performEntityCheck) { Debug.Assert(property != null, "property != null"); Debug.Assert(atomProperty != null, "atomProperty != null"); ODataResourceSet feed = atomProperty.Value as ODataResourceSet; ODataResource entry = atomProperty.Value as ODataResource; if (property.IsKnownType && (feed != null || entry != null)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkLocalSimple); } Type propertyType = null; if (feed != null) { // We need to fail if the payload states that the property is a navigation collection property // and in the client, the property is not a collection property. if (!property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } propertyType = property.EntityCollectionItemType; } if (entry != null) { if (property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } propertyType = property.PropertyType; } // If the server type and the client type does not match, we need to throw. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (propertyType != null && performEntityCheck) { if (!ClientTypeUtil.TypeIsEntity(propertyType, model)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString())); } } }
/// <summary> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="link"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="link">Property as parsed.</param> /// <param name="model">Client Model.</param> /// <param name="performEntityCheck">whether to do the entity check or not.</param> /// <returns>The type</returns> internal static Type ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNestedResourceInfo link, ClientEdmModel model, bool performEntityCheck) { Debug.Assert(property != null, "property != null"); Debug.Assert(link != null, "link != null"); Type propertyType = null; if (link.IsCollection.HasValue) { if (link.IsCollection.Value) { // We need to fail if the payload states that the property is a navigation collection property or a complex collection property // and in the client, the property is not a collection property. if (!property.IsResourceSet) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } propertyType = property.ResourceSetItemType; } else { if (property.IsResourceSet) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } propertyType = property.PropertyType; } } // If the server type and the client type does not match, we need to throw. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (propertyType != null && performEntityCheck) { if (!ClientTypeUtil.TypeIsStructured(propertyType, model)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString())); } } return(propertyType); }
/// <summary> /// Creates a new instance of MaterializerEntry. /// </summary> /// <param name="entry">The entry.</param> /// <param name="format">The format the entry was read in.</param> /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param> /// <param name="model">The client model.</param> private MaterializerEntry(ODataEntry entry, ODataFormat format, bool isTracking, ClientEdmModel model) { Debug.Assert(entry != null, "entry != null"); this.entry = entry; this.Format = format; this.entityDescriptor = new EntityDescriptor(model); #pragma warning disable 618 this.isAtomOrTracking = isTracking || this.Format == ODataFormat.Atom; #pragma warning restore 618 string serverTypeName = this.Entry.TypeName; SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { // If the annotation has a value use it. Otherwise, in JSON-Light, the types can be inferred from the // context URI even if they are not present on the wire, so just use the type name from the entry. if (serializationTypeNameAnnotation.TypeName != null || this.Format != ODataFormat.Json) { serverTypeName = serializationTypeNameAnnotation.TypeName; } } this.entityDescriptor.ServerTypeName = serverTypeName; }
/// <summary> /// Creates the materializer entry. /// </summary> /// <param name="entry">The entry.</param> /// <param name="format">The format the entry was read in.</param> /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param> /// <param name="model">The client model.</param> /// <returns>A new materializer entry.</returns> public static MaterializerEntry CreateEntry(ODataEntry entry, ODataFormat format, bool isTracking, ClientEdmModel model) { Debug.Assert(entry.GetAnnotation <MaterializerEntry>() == null, "MaterializerEntry has already been created."); MaterializerEntry materializerEntry = new MaterializerEntry(entry, format, isTracking, model); entry.SetAnnotation <MaterializerEntry>(materializerEntry); return(materializerEntry); }
public TestClientContext(Uri serviceRoot, ODataProtocolVersion version, ClientEdmModel model) : base(serviceRoot, version, model) { }
/// <summary> /// Is the type an structured type? /// </summary> /// <param name="t">Type to examine</param> /// <param name="model">The client model.</param> /// <returns>bool indicating whether or not structured type</returns> internal static bool TypeIsStructured(Type t, ClientEdmModel model) { var typeKind = model.GetOrCreateEdmType(t).TypeKind; return(typeKind == EdmTypeKind.Entity || typeKind == EdmTypeKind.Complex); }
/// <summary> /// Is the type a Complex Type? /// </summary> /// <param name="t">Type to examine</param> /// <param name="model">The client model.</param> /// <returns>bool indicating whether or not complex type</returns> internal static bool TypeIsComplex(Type t, ClientEdmModel model) { return(model.GetOrCreateEdmType(t).TypeKind == EdmTypeKind.Complex); }
/// <summary> /// Is the type an Entity Type? /// </summary> /// <param name="t">Type to examine</param> /// <param name="model">The client model.</param> /// <returns>bool indicating whether or not entity type</returns> internal static bool TypeIsEntity(Type t, ClientEdmModel model) { return(model.GetOrCreateEdmType(t).TypeKind == EdmTypeKind.Entity); }
/// <summary> /// Initializes a new instance of the <see cref="EntityTrackingAdapter" /> class. /// </summary> /// <param name="entityTracker">The entity tracker.</param> /// <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) { this.MaterializationLog = new AtomMaterializerLog(mergeOption, model, entityTracker); this.MergeOption = mergeOption; this.EntityTracker = entityTracker; this.Model = model; this.Context = context; }
/// <summary> /// gets the UriTranslateResult for a the query /// </summary> /// <param name="model">The client model.</param> /// <returns>an instance of QueryComponents.</returns> internal override QueryComponents QueryComponents(ClientEdmModel model) { return(this.Translate()); }