Esempio n. 1
0
        /// <summary>
        /// Attempts to find a pre-configured structural type or a primitive type or an enum type that matches the T.
        /// If no matches are found NULL is returned.
        /// </summary>
        public IEdmTypeConfiguration GetTypeConfigurationOrNull(Type type)
        {
            if (_primitiveTypes.ContainsKey(type))
            {
                return(_primitiveTypes[type]);
            }
            else
            {
                IEdmPrimitiveType          edmType       = EdmLibHelpers.GetEdmPrimitiveTypeOrNull(type);
                PrimitiveTypeConfiguration primitiveType = null;
                if (edmType != null)
                {
                    primitiveType         = new PrimitiveTypeConfiguration(this, edmType, type);
                    _primitiveTypes[type] = primitiveType;
                    return(primitiveType);
                }
                else if (_structuralTypes.ContainsKey(type))
                {
                    return(_structuralTypes[type]);
                }
                else if (_enumTypes.ContainsKey(type))
                {
                    return(_enumTypes[type]);
                }
            }

            return(null);
        }
Esempio n. 2
0
        /// <summary>
        /// Determines whether the given type is a primitive type or
        /// is a <see cref="string"/>, <see cref="DateTime"/>, <see cref="Decimal"/>,
        /// <see cref="Guid"/>, <see cref="DateTimeOffset"/> or <see cref="TimeSpan"/>.
        /// </summary>
        /// <param name="type">The type</param>
        /// <returns><c>true</c> if the type is a primitive type.</returns>
        internal static bool IsQueryPrimitiveType(Type type)
        {
            Contract.Assert(type != null);

            type = GetInnerMostElementType(type);

            return(TypeHelper.IsEnum(type) ||
                   TypeHelper.IsPrimitive(type) ||
                   type == typeof(Uri) ||
                   (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(type) != null));
        }
Esempio n. 3
0
        private static PropertyConfiguration GetKeyProperty(EntityTypeConfiguration entityType)
        {
            IEnumerable <PropertyConfiguration> keys =
                entityType.Properties
                .Where(p => (p.Name.Equals(entityType.Name + "Id", StringComparison.OrdinalIgnoreCase) || p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase)) &&
                       (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(p.PropertyInfo.PropertyType) != null || TypeHelper.IsEnum(p.PropertyInfo.PropertyType)));

            if (keys.Count() == 1)
            {
                return(keys.Single());
            }

            return(null);
        }
        /// <summary>
        /// Adds a primitive property to this edm type.
        /// </summary>
        /// <param name="propertyInfo">The property being added.</param>
        /// <returns>The <see cref="PrimitivePropertyConfiguration"/> so that the property can be configured further.</returns>
        public virtual PrimitivePropertyConfiguration AddProperty(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                throw Error.ArgumentNull("propertyInfo");
            }

            if (!TypeHelper.GetReflectedType(propertyInfo).IsAssignableFrom(ClrType))
            {
                throw Error.Argument("propertyInfo", SRResources.PropertyDoesNotBelongToType, propertyInfo.Name, ClrType.FullName);
            }

            ValidatePropertyNotAlreadyDefinedInBaseTypes(propertyInfo);
            ValidatePropertyNotAlreadyDefinedInDerivedTypes(propertyInfo);

            // Remove from the ignored properties
            if (RemovedProperties.Any(prop => prop.Name.Equals(propertyInfo.Name, StringComparison.Ordinal)))
            {
                RemovedProperties.Remove(RemovedProperties.First(prop => prop.Name.Equals(propertyInfo.Name, StringComparison.Ordinal)));
            }

            PrimitivePropertyConfiguration propertyConfiguration =
                ValidatePropertyNotAlreadyDefinedOtherTypes <PrimitivePropertyConfiguration>(propertyInfo,
                                                                                             SRResources.MustBePrimitiveProperty);

            if (propertyConfiguration == null)
            {
                propertyConfiguration = new PrimitivePropertyConfiguration(propertyInfo, this);
                var primitiveType = EdmLibHelpers.GetEdmPrimitiveTypeOrNull(propertyInfo.PropertyType);
                if (primitiveType != null)
                {
                    if (primitiveType.PrimitiveKind == EdmPrimitiveTypeKind.Decimal)
                    {
                        propertyConfiguration = new DecimalPropertyConfiguration(propertyInfo, this);
                    }
                    else if (EdmLibHelpers.HasLength(primitiveType.PrimitiveKind))
                    {
                        propertyConfiguration = new LengthPropertyConfiguration(propertyInfo, this);
                    }
                    else if (EdmLibHelpers.HasPrecision(primitiveType.PrimitiveKind))
                    {
                        propertyConfiguration = new PrecisionPropertyConfiguration(propertyInfo, this);
                    }
                }
                ExplicitProperties[propertyInfo] = propertyConfiguration;
            }

            return(propertyConfiguration);
        }
Esempio n. 5
0
        private bool ValidateConstraint(KeyValuePair <PropertyInfo, PropertyInfo> constraint)
        {
            if (_referentialConstraint.Contains(constraint))
            {
                return(true);
            }

            PropertyInfo value;

            if (_referentialConstraint.TryGetValue(constraint.Key, out value))
            {
                throw Error.InvalidOperation(SRResources.ReferentialConstraintAlreadyConfigured, "dependent",
                                             constraint.Key.Name, "principal", value.Name);
            }

            if (PrincipalProperties.Any(p => p == constraint.Value))
            {
                PropertyInfo foundDependent = _referentialConstraint.First(r => r.Value == constraint.Value).Key;

                throw Error.InvalidOperation(SRResources.ReferentialConstraintAlreadyConfigured, "principal",
                                             constraint.Value.Name, "dependent", foundDependent.Name);
            }

            Type dependentType = System.Nullable.GetUnderlyingType(constraint.Key.PropertyType) ?? constraint.Key.PropertyType;
            Type principalType = System.Nullable.GetUnderlyingType(constraint.Value.PropertyType) ?? constraint.Value.PropertyType;

            // The principal property and the dependent property must have the same data type.
            if (dependentType != principalType)
            {
                throw Error.InvalidOperation(SRResources.DependentAndPrincipalTypeNotMatch,
                                             constraint.Key.PropertyType.FullName, constraint.Value.PropertyType.FullName);
            }

            // OData V4 spec says that the principal and dependent property MUST be a path expression resolving to a primitive
            // property of the dependent entity type itself or to a primitive property of a complex property (recursively) of
            // the dependent entity type.
            // So far, ODL doesn't support to allow a primitive property of a complex property to be the dependent/principal property.
            // There's an issue tracking on: https://github.com/OData/odata.net/issues/22
            if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(constraint.Key.PropertyType) == null)
            {
                throw Error.InvalidOperation(SRResources.ReferentialConstraintPropertyTypeNotValid,
                                             constraint.Key.PropertyType.FullName);
            }

            return(false);
        }
        // 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);
                }
            }
        }
        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);
        }