// 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);
                }
            }
        }
Example #2
0
 /// <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);
        }