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