// 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 if (currentType.Kind == EdmTypeKind.Entity) { EntityTypeConfiguration currentEntityType = (EntityTypeConfiguration)currentType; 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); } } } else if (currentType.Kind == EdmTypeKind.Complex) { ComplexTypeConfiguration currentComplexType = (ComplexTypeConfiguration)currentType; if (currentComplexType.BaseType != null && !visitedTypes.Contains(currentComplexType.BaseType)) { reachableTypes.Enqueue(currentComplexType.BaseType); } foreach (ComplexTypeConfiguration derivedType in this.DerivedTypes(currentComplexType)) { 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); } } }
/// <summary> /// Initializes a new instance of the <see cref="StructuralPropertyConfiguration"/> class. /// </summary> /// <param name="property">The property of the configuration.</param> /// <param name="declaringType">The declaring type of the property.</param> protected StructuralPropertyConfiguration(PropertyInfo property, StructuralTypeConfiguration declaringType) : base(property, declaringType) { NullableProperty = EdmLibHelpers.IsNullable(property.PropertyType); }
private bool TryGetPropertyTypeKind(Type propertyType, out IEdmTypeConfiguration mappedType, out PropertyKind propertyKind) { Contract.Assert(propertyType != null); if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(propertyType) != null) { mappedType = null; propertyKind = PropertyKind.Primitive; return(true); } mappedType = GetStructuralTypeOrNull(propertyType); if (mappedType != null) { if (mappedType is ComplexTypeConfiguration) { propertyKind = PropertyKind.Complex; } else if (mappedType is EnumTypeConfiguration) { propertyKind = PropertyKind.Enum; } else { propertyKind = PropertyKind.Navigation; } return(true); } // If one of the base types is configured as complex type, the type of this property // should be configured as complex type too. Type baseType = TypeHelper.GetBaseType(propertyType); while (baseType != null && baseType != typeof(object)) { IEdmTypeConfiguration baseMappedType = GetStructuralTypeOrNull(baseType); if (baseMappedType != null) { if (baseMappedType is ComplexTypeConfiguration) { propertyKind = PropertyKind.Complex; return(true); } } baseType = TypeHelper.GetBaseType(baseType); } // refer the Edm type from the derived types PropertyKind referedPropertyKind = PropertyKind.Navigation; if (InferEdmTypeFromDerivedTypes(propertyType, ref referedPropertyKind)) { if (referedPropertyKind == PropertyKind.Complex) { ReconfigInferedEntityTypeAsComplexType(propertyType); } propertyKind = referedPropertyKind; return(true); } if (TypeHelper.IsEnum(propertyType)) { propertyKind = PropertyKind.Enum; return(true); } propertyKind = PropertyKind.Navigation; return(false); }