diff options
author | raghuramn <ranadimi@microsoft.com> | 2012-09-15 03:37:41 +0400 |
---|---|---|
committer | raghuramn <ranadimi@microsoft.com> | 2012-09-24 21:48:38 +0400 |
commit | 062399f30f077caa26947be4ae1d525df8227b97 (patch) | |
tree | 114471333216dc47a76d3420f96aa6f51989f1ec | |
parent | bc22f1bdcca80b04fe18abc19df46d2e026edfb8 (diff) |
Enabling skipped ODataConventionBuilder test.
The earlier commit adding collection property did not fix the convention
model builder fully. we throw a NotSupportedException if a complex type
has a collection property. This commit fixes that.
4 files changed, 189 insertions, 45 deletions
diff --git a/src/System.Web.Http.OData/OData/Builder/ODataConventionModelBuilder.cs b/src/System.Web.Http.OData/OData/Builder/ODataConventionModelBuilder.cs index 65ab320e..715153ff 100644 --- a/src/System.Web.Http.OData/OData/Builder/ODataConventionModelBuilder.cs +++ b/src/System.Web.Http.OData/OData/Builder/ODataConventionModelBuilder.cs @@ -196,17 +196,18 @@ namespace System.Web.Http.OData.Builder .ToArray(); foreach (NavigationPropertyConfiguration propertyToBeRemoved in propertiesToBeRemoved) { + entityToBePatched.RemoveProperty(propertyToBeRemoved.PropertyInfo); + if (propertyToBeRemoved.Multiplicity == EdmMultiplicity.Many) { - // complex collections are not supported. - throw Error.NotSupported(SRResources.CollectionPropertiesNotSupported, propertyToBeRemoved.PropertyInfo.Name, propertyToBeRemoved.PropertyInfo.ReflectedType.FullName); + entityToBePatched.AddCollectionProperty(propertyToBeRemoved.PropertyInfo); + } + else + { + entityToBePatched.AddComplexProperty(propertyToBeRemoved.PropertyInfo); } - entityToBePatched.RemoveProperty(propertyToBeRemoved.PropertyInfo); - entityToBePatched.AddComplexProperty(propertyToBeRemoved.PropertyInfo); } } - - AddComplexType(misconfiguredEntityType.ClrType); } } @@ -271,32 +272,26 @@ namespace System.Web.Http.OData.Builder else { // navigation property in a complex type ? - if (!isCollection) + if (mappedType == null) { - if (mappedType == null) - { - // the user told nothing about this type and this is the first time we are seeing this type. - // complex types cannot contain entities. So, treat it as complex property. - complexType.AddComplexProperty(property); - } - else - { - if (_explicitlyAddedTypes.Contains(mappedType)) - { - // user told us that this an entity type. - throw Error.InvalidOperation(SRResources.ComplexTypeRefersToEntityType, complexType.ClrType.FullName, mappedType.ClrType.FullName, property.Name); - } - else - { - // we tried to be over-smart earlier and made the bad choice. so patch up now. - ReconfigureEntityTypesAsComplexType(new IEntityTypeConfiguration[] { mappedType as IEntityTypeConfiguration }); - complexType.AddComplexProperty(property); - } - } + // the user told nothing about this type and this is the first time we are seeing this type. + // complex types cannot contain entities. So, treat it as complex property. + MapStructuralProperty(complexType, property, PropertyKind.Complex, isCollection); + } + else if (_explicitlyAddedTypes.Contains(mappedType)) + { + // user told us that this is an entity type. + throw Error.InvalidOperation(SRResources.ComplexTypeRefersToEntityType, complexType.ClrType.FullName, mappedType.ClrType.FullName, property.Name); } else { - throw Error.NotSupported(SRResources.CollectionPropertiesNotSupported, property.Name, property.ReflectedType.FullName); + // we tried to be over-smart earlier and made the bad choice. so patch up now. + IEntityTypeConfiguration mappedTypeAsEntity = mappedType as IEntityTypeConfiguration; + Contract.Assert(mappedTypeAsEntity != null); + + ReconfigureEntityTypesAsComplexType(new IEntityTypeConfiguration[] { mappedTypeAsEntity }); + + MapStructuralProperty(complexType, property, PropertyKind.Complex, isCollection); } } } @@ -306,7 +301,7 @@ namespace System.Web.Http.OData.Builder { Contract.Assert(type != null); Contract.Assert(property != null); - Contract.Assert(propertyKind == PropertyKind.Complex || propertyKind == PropertyKind.Primitive || propertyKind == PropertyKind.Collection); + Contract.Assert(propertyKind == PropertyKind.Complex || propertyKind == PropertyKind.Primitive); if (!isCollection) { @@ -330,7 +325,7 @@ namespace System.Web.Http.OData.Builder } } - // figures out the type of the property (primitive, complex, navigation, collecion) and the corresponding edm type if we have seen this type + // figures out the type of the property (primitive, complex, navigation) and the corresponding edm type if we have seen this type // earlier or the user told us about it. private PropertyKind GetPropertyType(PropertyInfo property, out bool isCollection, out IStructuralTypeConfiguration mappedType) { @@ -379,12 +374,16 @@ namespace System.Web.Http.OData.Builder } else { + // if we know nothing about this type we assume it to be an entity + // and patch up later return PropertyKind.Navigation; } } } else { + // if we know nothing about this type we assume it to be an entity + // and patch up later isCollection = false; return PropertyKind.Navigation; } diff --git a/src/System.Web.Http.OData/Properties/SRResources.Designer.cs b/src/System.Web.Http.OData/Properties/SRResources.Designer.cs index b9d46ea7..c92fb845 100644 --- a/src/System.Web.Http.OData/Properties/SRResources.Designer.cs +++ b/src/System.Web.Http.OData/Properties/SRResources.Designer.cs @@ -196,16 +196,7 @@ namespace System.Web.Http.OData.Properties { } /// <summary> - /// Looks up a localized string similar to The property '{0}' on type '{1}' is a collection property. Collection properties are not supported.. - /// </summary> - internal static string CollectionPropertiesNotSupported { - get { - return ResourceManager.GetString("CollectionPropertiesNotSupported", resourceCulture); - } - } - - /// <summary> - /// Looks up a localized string similar to The complex type '{0}' refers to the entity type '{1}' through the property '{1}'.. + /// Looks up a localized string similar to The complex type '{0}' refers to the entity type '{1}' through the property '{2}'.. /// </summary> internal static string ComplexTypeRefersToEntityType { get { diff --git a/src/System.Web.Http.OData/Properties/SRResources.resx b/src/System.Web.Http.OData/Properties/SRResources.resx index 203d445c..47468f69 100644 --- a/src/System.Web.Http.OData/Properties/SRResources.resx +++ b/src/System.Web.Http.OData/Properties/SRResources.resx @@ -318,11 +318,8 @@ <data name="PrimitiveTypeRequired" xml:space="preserve"> <value>The type '{0}' is not a primitive type.</value> </data> - <data name="CollectionPropertiesNotSupported" xml:space="preserve"> - <value>The property '{0}' on type '{1}' is a collection property. Collection properties are not supported.</value> - </data> <data name="ComplexTypeRefersToEntityType" xml:space="preserve"> - <value>The complex type '{0}' refers to the entity type '{1}' through the property '{1}'.</value> + <value>The complex type '{0}' refers to the entity type '{1}' through the property '{2}'.</value> </data> <data name="MultipleAttributesFound" xml:space="preserve"> <value>The member '{0}' on type '{1}' contains multiple instances of the attribute '{2}'.</value> diff --git a/test/System.Web.Http.OData.Test/OData/Builder/Conventions/ODataConventionModelBuilderTests.cs b/test/System.Web.Http.OData.Test/OData/Builder/Conventions/ODataConventionModelBuilderTests.cs index 6cae7cd2..17b19f32 100644 --- a/test/System.Web.Http.OData.Test/OData/Builder/Conventions/ODataConventionModelBuilderTests.cs +++ b/test/System.Web.Http.OData.Test/OData/Builder/Conventions/ODataConventionModelBuilderTests.cs @@ -82,7 +82,7 @@ namespace System.Web.Http.OData.Builder.Conventions version.AssertHasPrimitiveProperty(model, "Minor", EdmPrimitiveTypeKind.Int32, isNullable: false); } - [Theory(Skip = "ODataConventionModelBuilder always treats unknown element types are Entities")] + [Theory] [InlineData(typeof(Version[]))] [InlineData(typeof(IEnumerable<Version>))] [InlineData(typeof(List<Version>))] @@ -375,6 +375,163 @@ namespace System.Web.Http.OData.Builder.Conventions Assert.NotNull(model); } + [Fact] + public void ComplexType_Containing_EntityCollection_Throws() + { + Type entityType = CreateDynamicType( + new DynamicType + { + TypeName = "EntityType" + }); + + Type complexType = CreateDynamicType( + new DynamicType + { + TypeName = "ComplexTypeWithEntityCollection", + Properties = + { + new DynamicProperty + { + Name = "CollectionProperty", + Type = CreateCollectionType(entityType) + } + } + }); + + var modelBuilder = new ODataConventionModelBuilder(); + modelBuilder.AddEntity(entityType); + modelBuilder.AddComplexType(complexType); + + Assert.Throws<InvalidOperationException>( + () => modelBuilder.GetEdmModel(), + "The complex type 'SampleNamespace.ComplexTypeWithEntityCollection' refers to the entity type 'SampleNamespace.EntityType' through the property 'CollectionProperty'."); + } + + [Fact] + public void ComplexType_Containing_ComplexCollection_works() + { + Type complexType = CreateDynamicType( + new DynamicType + { + TypeName = "ComplexTypeWithComplexCollection", + Properties = + { + new DynamicProperty + { + Name = "CollectionProperty", + Type = typeof(Version[]) + } + } + }); + + var modelBuilder = new ODataConventionModelBuilder(); + modelBuilder.AddComplexType(complexType); + + var model = modelBuilder.GetEdmModel(); + + IEdmComplexType complexEdmType = model.AssertHasComplexType(complexType); + model.AssertHasComplexType(typeof(Version)); + var collectionProperty = complexEdmType.DeclaredProperties.Where(p => p.Name == "CollectionProperty").SingleOrDefault(); + Assert.NotNull(collectionProperty); + Assert.True(collectionProperty.Type.IsCollection()); + Assert.Equal(collectionProperty.Type.AsCollection().ElementType().FullName(), "System.Version"); + } + + [Fact] + public void EntityType_Containing_ComplexCollection_Works() + { + Type entityType = CreateDynamicType( + new DynamicType + { + TypeName = "EntityTypeWithComplexCollection", + Properties = + { + new DynamicProperty + { + Name = "ID", + Type = typeof(int) + }, + new DynamicProperty + { + Name = "CollectionProperty", + Type = typeof(Version[]) + } + } + }); + + var modelBuilder = new ODataConventionModelBuilder(); + modelBuilder.AddEntity(entityType); + + var model = modelBuilder.GetEdmModel(); + + IEdmEntityType entityEdmType = model.AssertHasEntityType(entityType); + model.AssertHasComplexType(typeof(Version)); + var collectionProperty = entityEdmType.DeclaredProperties.Where(p => p.Name == "CollectionProperty").SingleOrDefault(); + Assert.NotNull(collectionProperty); + Assert.True(collectionProperty.Type.IsCollection()); + Assert.Equal(collectionProperty.Type.AsCollection().ElementType().FullName(), "System.Version"); + } + + [Fact] + public void EntityType_Containing_ComplexTypeContainingComplexCollection_Works() + { + Type complexTypeWithComplexCollection = CreateDynamicType( + new DynamicType + { + TypeName = "ComplexType", + Properties = + { + new DynamicProperty + { + Name = "ComplexCollectionProperty", + Type = typeof(Version[]) + } + } + }); + + Type entityType = CreateDynamicType( + new DynamicType + { + TypeName = "EntityTypeWithComplexCollection", + Properties = + { + new DynamicProperty + { + Name = "ID", + Type = typeof(int) + }, + new DynamicProperty + { + Name = "ComplexProperty", + Type = complexTypeWithComplexCollection + } + } + }); + + var modelBuilder = new ODataConventionModelBuilder(); + modelBuilder.AddEntity(entityType); + + var model = modelBuilder.GetEdmModel(); + + IEdmEntityType entityEdmType = model.AssertHasEntityType(entityType); + model.AssertHasComplexType(typeof(Version)); + IEdmComplexType edmComplexType = model.AssertHasComplexType(complexTypeWithComplexCollection); + + var collectionProperty = edmComplexType.DeclaredProperties.Where(p => p.Name == "ComplexCollectionProperty").SingleOrDefault(); + Assert.NotNull(collectionProperty); + Assert.True(collectionProperty.Type.IsCollection()); + Assert.Equal(collectionProperty.Type.AsCollection().ElementType().FullName(), "System.Version"); + } + + private static Type CreateCollectionType(Type type) + { + Mock<Type> collectionType = new Mock<Type>(); + collectionType.Setup(t => t.Namespace).Returns("SampleNamespace"); + collectionType.Setup(t => t.FullName).Returns("SampleNamespace." + "CollectionType"); + collectionType.Setup(t => t.GetInterfaces()).Returns(new Type[] { typeof(IEnumerable<>).MakeGenericType(type) }); + return collectionType.Object; + } + private static Type CreateDynamicType(DynamicType dynamicType) { Mock<Type> type = new Mock<Type>(); |