/// <summary> /// Adds a collection property to this edm type. /// </summary> /// <param name="propertyInfo">The property being added.</param> /// <returns>The <see cref="CollectionPropertyConfiguration"/> so that the property can be configured further.</returns> public virtual CollectionPropertyConfiguration AddCollectionProperty(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw Error.ArgumentNull("propertyInfo"); } if (!propertyInfo.DeclaringType.IsAssignableFrom(ClrType)) { throw Error.Argument("propertyInfo", SRResources.PropertyDoesNotBelongToType); } ValidatePropertyNotAlreadyDefinedInBaseTypes(propertyInfo); ValidatePropertyNotAlreadyDefinedInDerivedTypes(propertyInfo); // Remove from the ignored properties if (RemovedProperties.Any(prop => prop.Name.Equals(propertyInfo.Name))) { RemovedProperties.Remove(RemovedProperties.First(prop => prop.Name.Equals(propertyInfo.Name))); } CollectionPropertyConfiguration propertyConfiguration = ValidatePropertyNotAlreadyDefinedOtherTypes <CollectionPropertyConfiguration>(propertyInfo, SRResources.MustBeCollectionProperty); if (propertyConfiguration == null) { propertyConfiguration = new CollectionPropertyConfiguration(propertyInfo, this); ExplicitProperties[propertyInfo] = propertyConfiguration; // If the ElementType is the same as this type this is recursive complex type nesting if (propertyConfiguration.ElementType == ClrType) { throw Error.Argument("propertyInfo", SRResources.RecursiveComplexTypesNotAllowed, ClrType.Name, propertyConfiguration.Name); } // If the ElementType is not primitive or enum treat as a ComplexType and Add to the model. IEdmPrimitiveTypeReference edmType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(propertyConfiguration.ElementType); if (edmType == null) { if (!TypeHelper.IsEnum(propertyConfiguration.ElementType)) { ModelBuilder.AddComplexType(propertyConfiguration.ElementType); } } } return(propertyConfiguration); }
public void HasCorrectKindPropertyInfoAndName(PropertyInfo property, Type elementType) { Mock <StructuralTypeConfiguration> structuralType = new Mock <StructuralTypeConfiguration>(); CollectionPropertyConfiguration configuration = new CollectionPropertyConfiguration(property, structuralType.Object); Assert.Equal(PropertyKind.Collection, configuration.Kind); Assert.Equal(elementType, configuration.ElementType); Assert.Equal(elementType, configuration.RelatedClrType); Assert.Equal(property, configuration.PropertyInfo); Assert.Equal(property.Name, configuration.Name); Assert.Equal(structuralType.Object, configuration.DeclaringType); }
public void HasManyPath_AddBindindPath_Derived(bool contained) { // Assert ODataModelBuilder builder = new ODataModelBuilder(); var customerType = builder.EntityType <BindingCustomer>(); var navigationSource = builder.EntitySet <BindingCustomer>("Customers"); StructuralTypeConfiguration addressType = builder.StructuralTypes.FirstOrDefault(c => c.Name == "BindingAddress"); Assert.Null(addressType); // Guard Assert.Empty(customerType.Properties); // Guard // Act var binding = new BindingPathConfiguration <BindingCustomer>(builder, customerType, navigationSource.Configuration); var newBinding = binding.HasManyPath((BindingVipCustomer v) => v.VipAddresses, contained); // Assert addressType = builder.StructuralTypes.FirstOrDefault(c => c.Name == "BindingAddress"); Assert.NotNull(addressType); Assert.Empty(customerType.Properties); StructuralTypeConfiguration vipCustomerType = builder.StructuralTypes.FirstOrDefault(c => c.Name == "BindingVipCustomer"); Assert.NotNull(vipCustomerType); var vipAddressesProperty = Assert.Single(vipCustomerType.Properties); Assert.Equal("VipAddresses", vipAddressesProperty.Name); if (contained) { Assert.Equal(EdmTypeKind.Entity, addressType.Kind); Assert.Equal(PropertyKind.Navigation, vipAddressesProperty.Kind); NavigationPropertyConfiguration navigationProperty = Assert.IsType <NavigationPropertyConfiguration>(vipAddressesProperty); Assert.Equal(EdmMultiplicity.Many, navigationProperty.Multiplicity); Assert.True(navigationProperty.ContainsTarget); } else { Assert.Equal(EdmTypeKind.Complex, addressType.Kind); Assert.Equal(PropertyKind.Collection, vipAddressesProperty.Kind); CollectionPropertyConfiguration collection = Assert.IsType <CollectionPropertyConfiguration>(vipAddressesProperty); Assert.Equal(typeof(BindingAddress), collection.ElementType); } // different bindings Assert.NotSame(binding, newBinding); Assert.Equal("", binding.BindingPath); Assert.IsType <BindingPathConfiguration <BindingAddress> >(newBinding); Assert.Equal("System.Web.OData.Formatter.BindingVipCustomer/VipAddresses", newBinding.BindingPath); }
private static void FindNavigationProperties(this ODataModelBuilder builder, StructuralTypeConfiguration configuration, IList <Tuple <StructuralTypeConfiguration, IList <MemberInfo>, NavigationPropertyConfiguration> > navs, Stack <MemberInfo> path) { Contract.Assert(builder != null); Contract.Assert(configuration != null); Contract.Assert(navs != null); Contract.Assert(path != null); foreach (var property in configuration.Properties) { path.Push(property.PropertyInfo); NavigationPropertyConfiguration nav = property as NavigationPropertyConfiguration; ComplexPropertyConfiguration complex = property as ComplexPropertyConfiguration; CollectionPropertyConfiguration collection = property as CollectionPropertyConfiguration; if (nav != null) { // how about the containment? IList <MemberInfo> bindingPath = path.Reverse().ToList(); navs.Add( new Tuple <StructuralTypeConfiguration, IList <MemberInfo>, NavigationPropertyConfiguration>(configuration, bindingPath, nav)); } else if (complex != null) { StructuralTypeConfiguration complexType = builder.GetTypeConfigurationOrNull(complex.RelatedClrType) as StructuralTypeConfiguration; builder.FindAllNavigationProperties(complexType, navs, path); } else if (collection != null) { IEdmTypeConfiguration edmType = builder.GetTypeConfigurationOrNull(collection.ElementType); if (edmType != null && edmType.Kind == EdmTypeKind.Complex) { StructuralTypeConfiguration complexType = (StructuralTypeConfiguration)edmType; builder.FindAllNavigationProperties(complexType, navs, path); } } path.Pop(); } }
// the convention model builder MapTypes() method might have went through deep object graphs and added a bunch of types // only to realise after applying the conventions that the user has ignored some of the properties. So, prune the unreachable stuff. private void PruneUnreachableTypes() { Contract.Assert(_explicitlyAddedTypes != null); // Do a BFS starting with the types the user has explicitly added to find out the unreachable nodes. Queue <StructuralTypeConfiguration> reachableTypes = new Queue <StructuralTypeConfiguration>(_explicitlyAddedTypes); HashSet <StructuralTypeConfiguration> visitedTypes = new HashSet <StructuralTypeConfiguration>(); while (reachableTypes.Count != 0) { StructuralTypeConfiguration currentType = reachableTypes.Dequeue(); // go visit other end of each of this node's edges. foreach (PropertyConfiguration property in currentType.Properties.Where(property => property.Kind != PropertyKind.Primitive)) { if (property.Kind == PropertyKind.Collection) { // if the elementType is primitive we don't need to do anything. CollectionPropertyConfiguration colProperty = property as CollectionPropertyConfiguration; if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(colProperty.ElementType) != null) { continue; } } IEdmTypeConfiguration propertyType = GetStructuralTypeOrNull(property.RelatedClrType); Contract.Assert(propertyType != null, "we should already have seen this type"); var structuralTypeConfiguration = propertyType as StructuralTypeConfiguration; if (structuralTypeConfiguration != null && !visitedTypes.Contains(propertyType)) { reachableTypes.Enqueue(structuralTypeConfiguration); } } // all derived types and the base type are also reachable EntityTypeConfiguration currentEntityType = currentType as EntityTypeConfiguration; if (currentEntityType != null) { if (currentEntityType.BaseType != null && !visitedTypes.Contains(currentEntityType.BaseType)) { reachableTypes.Enqueue(currentEntityType.BaseType); } foreach (EntityTypeConfiguration derivedType in this.DerivedTypes(currentEntityType)) { if (!visitedTypes.Contains(derivedType)) { reachableTypes.Enqueue(derivedType); } } } visitedTypes.Add(currentType); } StructuralTypeConfiguration[] allConfiguredTypes = StructuralTypes.ToArray(); foreach (StructuralTypeConfiguration type in allConfiguredTypes) { if (!visitedTypes.Contains(type)) { // we don't have to fix up any properties because this type is unreachable and cannot be a property of any reachable type. RemoveStructuralType(type.ClrType); } } }
private IEdmProperty CreateStructuralTypeCollectionPropertyBody(EdmStructuredType type, CollectionPropertyConfiguration collectionProperty) { IEdmTypeReference elementTypeReference = null; Type clrType = TypeHelper.GetUnderlyingTypeOrSelf(collectionProperty.ElementType); if (clrType.IsEnum) { IEdmType edmType = GetEdmType(clrType); if (edmType == null) { throw Error.InvalidOperation(SRResources.EnumTypeDoesNotExist, clrType.Name); } IEdmEnumType enumElementType = (IEdmEnumType)edmType; bool isNullable = collectionProperty.ElementType != clrType; elementTypeReference = new EdmEnumTypeReference(enumElementType, isNullable); } else { IEdmType edmType = GetEdmType(collectionProperty.ElementType); if (edmType != null) { IEdmComplexType elementType = edmType as IEdmComplexType; Contract.Assert(elementType != null); elementTypeReference = new EdmComplexTypeReference(elementType, collectionProperty.OptionalProperty); } else { elementTypeReference = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(collectionProperty.ElementType); Contract.Assert(elementTypeReference != null); } } return type.AddStructuralProperty( collectionProperty.Name, new EdmCollectionTypeReference(new EdmCollectionType(elementTypeReference))); }
private IEdmProperty CreateStructuralTypeCollectionPropertyBody(EdmStructuredType type, CollectionPropertyConfiguration collectionProperty) { IEdmTypeReference elementTypeReference = null; Type clrType = TypeHelper.GetUnderlyingTypeOrSelf(collectionProperty.ElementType); if (clrType.IsEnum) { IEdmType edmType = GetEdmType(clrType); if (edmType == null) { throw Error.InvalidOperation(SRResources.EnumTypeDoesNotExist, clrType.Name); } IEdmEnumType enumElementType = (IEdmEnumType)edmType; bool isNullable = collectionProperty.ElementType != clrType; elementTypeReference = new EdmEnumTypeReference(enumElementType, isNullable); } else { IEdmType edmType = GetEdmType(collectionProperty.ElementType); if (edmType != null) { IEdmComplexType elementType = edmType as IEdmComplexType; Contract.Assert(elementType != null); elementTypeReference = new EdmComplexTypeReference(elementType, collectionProperty.OptionalProperty); } else { elementTypeReference = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(collectionProperty.ElementType); Contract.Assert(elementTypeReference != null); } } return(type.AddStructuralProperty( collectionProperty.Name, new EdmCollectionTypeReference(new EdmCollectionType(elementTypeReference)))); }
/// <summary> /// Adds a collection property to this edm type. /// </summary> /// <param name="propertyInfo">The property being added.</param> /// <returns>The <see cref="CollectionPropertyConfiguration"/> so that the property can be configured further.</returns> public virtual CollectionPropertyConfiguration AddCollectionProperty(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw Error.ArgumentNull("propertyInfo"); } if (!propertyInfo.DeclaringType.IsAssignableFrom(ClrType)) { throw Error.Argument("propertyInfo", SRResources.PropertyDoesNotBelongToType); } // Remove from the ignored properties if (IgnoredProperties.Contains(propertyInfo)) { RemovedProperties.Remove(propertyInfo); } CollectionPropertyConfiguration propertyConfiguration; if (ExplicitProperties.ContainsKey(propertyInfo)) { propertyConfiguration = ExplicitProperties[propertyInfo] as CollectionPropertyConfiguration; if (propertyConfiguration == null) { throw Error.Argument("propertyInfo", SRResources.MustBeCollectionProperty, propertyInfo.Name, propertyInfo.DeclaringType.FullName); } } else { Type elementType; if (propertyInfo.PropertyType.IsCollection(out elementType) && ( elementType == typeof(DateTime) || elementType == typeof(DateTime?))) { throw Error.Argument("propertyInfo", SRResources.DateTimeTypePropertyNotSupported, propertyInfo.PropertyType.FullName, propertyInfo.Name, propertyInfo.DeclaringType.FullName, typeof(DateTimeOffset).FullName, typeof(ODataModelBuilder).FullName); } propertyConfiguration = new CollectionPropertyConfiguration(propertyInfo, this); ExplicitProperties[propertyInfo] = propertyConfiguration; // If the ElementType is the same as this type this is recursive complex type nesting if (propertyConfiguration.ElementType == ClrType) { throw Error.Argument("propertyInfo", SRResources.RecursiveComplexTypesNotAllowed, ClrType.Name, propertyConfiguration.Name); } // If the ElementType is not primitive or enum treat as a ComplexType and Add to the model. IEdmPrimitiveTypeReference edmType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(propertyConfiguration.ElementType); if (edmType == null) { if (!TypeHelper.IsEnum(propertyConfiguration.ElementType)) { ModelBuilder.AddComplexType(propertyConfiguration.ElementType); } } } return(propertyConfiguration); }
/// <summary> /// Adds a collection property to this edm type. /// </summary> /// <param name="propertyInfo">The property being added.</param> /// <returns>The <see cref="CollectionPropertyConfiguration"/> so that the property can be configured further.</returns> public virtual CollectionPropertyConfiguration AddCollectionProperty(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw Error.ArgumentNull("propertyInfo"); } if (!propertyInfo.DeclaringType.IsAssignableFrom(ClrType)) { throw Error.Argument("propertyInfo", SRResources.PropertyDoesNotBelongToType); } // Remove from the ignored properties if (IgnoredProperties.Contains(propertyInfo)) { RemovedProperties.Remove(propertyInfo); } CollectionPropertyConfiguration propertyConfiguration; if (ExplicitProperties.ContainsKey(propertyInfo)) { propertyConfiguration = ExplicitProperties[propertyInfo] as CollectionPropertyConfiguration; if (propertyConfiguration == null) { throw Error.Argument("propertyInfo", SRResources.MustBeCollectionProperty, propertyInfo.Name, propertyInfo.DeclaringType.FullName); } } else { propertyConfiguration = new CollectionPropertyConfiguration(propertyInfo, this); ExplicitProperties[propertyInfo] = propertyConfiguration; // If the ElementType is the same as this type this is recursive complex type nesting if (propertyConfiguration.ElementType == ClrType) { throw Error.Argument("propertyInfo", SRResources.RecursiveComplexTypesNotAllowed, ClrType.Name, propertyConfiguration.Name); } // If the ElementType is not primitive or enum treat as a ComplexType and Add to the model. IEdmPrimitiveTypeReference edmType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(propertyConfiguration.ElementType); if (edmType == null) { if (!TypeHelper.IsEnum(propertyConfiguration.ElementType)) { ModelBuilder.AddComplexType(propertyConfiguration.ElementType); } } } return propertyConfiguration; }