示例#1
0
        private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
        {
            Contract.Assert(edmModel != null);
            Contract.Assert(clrType != null);

            IEdmPrimitiveType primitiveType = GetEdmPrimitiveTypeOrNull(clrType);

            if (primitiveType != null)
            {
                return(primitiveType);
            }
            else
            {
                if (testCollections)
                {
                    Type enumerableOfT = ExtractGenericInterface(clrType, typeof(IEnumerable <>));
                    if (enumerableOfT != null)
                    {
                        Type elementClrType = enumerableOfT.GetGenericArguments()[0];

                        // IEnumerable<SelectExpandWrapper<T>> is a collection of T.
                        Type entityType;
                        if (IsSelectExpandWrapper(elementClrType, out entityType))
                        {
                            elementClrType = entityType;
                        }

                        IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
                        if (elementType != null)
                        {
                            return(new EdmCollectionType(elementType.ToEdmTypeReference(IsNullable(elementClrType))));
                        }
                    }
                }

                Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(clrType);

                if (underlyingType.IsEnum)
                {
                    clrType = underlyingType;
                }

                // search for the ClrTypeAnnotation and return it if present
                IEdmType returnType =
                    edmModel
                    .SchemaElements
                    .OfType <IEdmType>()
                    .Select(edmType => new { EdmType = edmType, Annotation = edmModel.GetAnnotationValue <ClrTypeAnnotation>(edmType) })
                    .Where(tuple => tuple.Annotation != null && tuple.Annotation.ClrType == clrType)
                    .Select(tuple => tuple.EdmType)
                    .SingleOrDefault();

                // default to the EdmType with the same name as the ClrType name
                returnType = returnType ?? edmModel.FindType(clrType.EdmFullName());

                if (clrType.BaseType != null)
                {
                    // go up the inheritance tree to see if we have a mapping defined for the base type.
                    returnType = returnType ?? GetEdmType(edmModel, clrType.BaseType, testCollections);
                }
                return(returnType);
            }
        }
示例#2
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(keyProperties != null, "keyProperties != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                Type collectionType;
                bool isOpen = false;
                if (EdmStructuredSchemaElements != null && EdmStructuredSchemaElements.Any())
                {
                    IEdmStructuredType edmStructuredType =
                        EdmStructuredSchemaElements.FirstOrDefault(
                            et => (et != null && et.Name == ClientTypeUtil.GetServerDefinedTypeName(type))) as IEdmStructuredType;
                    if (edmStructuredType != null)
                    {
                        isOpen = edmStructuredType.IsOpen;
                    }
                }

                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType primitiveType;
                    PrimitiveType.TryGetPrimitiveType(type, out primitiveType);
                    Debug.Assert(primitiveType != null, "primitiveType != null");
                    cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties);
                }
                else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)
                {
                    // Collection Type
                    Type     elementType = collectionType.GetGenericArguments()[0];
                    IEdmType itemType    = this.GetOrCreateEdmType(elementType);

                    // Note that
                    // 1. throw here because collection of a collection is not allowed
                    // 2. will also throw during SaveChanges(), validated by unit test case 'SerializationOfCollection'in CollectionTests.cs.
                    if ((itemType.TypeKind == EdmTypeKind.Collection))
                    {
                        throw new ODataException(Strings.ClientType_CollectionOfCollectionNotSupported);
                    }

                    cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties);
                }
                else
                {
                    Type enumTypeTmp = null;
                    if (isEntity)
                    {
                        Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) =>
                        {
                            // Create properties without modifying the entityType.
                            // This will leave entityType intact in case of an exception during loading.
                            List <IEdmProperty>           loadedProperties    = new List <IEdmProperty>();
                            List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
                                loadedProperties.Add(edmProperty);

                                if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
                                {
                                    Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
                                    Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive");
                                    loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
                                }
                            }

                            // Now add properties to the entityType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                entityType.AddProperty(property);
                            }

                            entityType.AddKeys(loadedKeyProperties);
                        };

                        // Creating an entity type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity");
                        bool hasStream = GetHasStreamValue((IEdmEntityType)edmBaseType, type);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), isOpen, hasStream, delayLoadEntityProperties),
                            hasProperties);
                    }
                    else if ((enumTypeTmp = Nullable.GetUnderlyingType(type) ?? type) != null &&
                             enumTypeTmp.IsEnum())
                    {
                        Action <EdmEnumTypeWithDelayLoadedMembers> delayLoadEnumMembers = (enumType) =>
                        {
#if DNXCORE50
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields().Where(fieldInfo => fieldInfo.IsStatic))
#else
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields(BindingFlags.Static | BindingFlags.Public))
#endif
                            {
                                object memberValue = Enum.Parse(enumTypeTmp, tmp.Name, false);
                                enumType.AddMember(new EdmEnumMember(enumType, tmp.Name, new EdmIntegerConstant((long)Convert.ChangeType(memberValue, typeof(long), CultureInfo.InvariantCulture.NumberFormat))));
                            }
                        };

                        // underlying type may be Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32, or Edm.Int64.
                        Type underlyingType = Enum.GetUnderlyingType(enumTypeTmp);
                        IEdmPrimitiveType underlyingEdmType = (IEdmPrimitiveType)EdmCoreModel.Instance.FindDeclaredType("Edm." + underlyingType.Name);
                        Debug.Assert(underlyingEdmType != null, "underlyingEdmType != null");
                        bool isFlags = enumTypeTmp.GetCustomAttributes(false).Any(s => s is FlagsAttribute);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEnumTypeWithDelayLoadedMembers(CommonUtil.GetModelTypeNamespace(enumTypeTmp), CommonUtil.GetModelTypeName(enumTypeTmp), underlyingEdmType, isFlags, delayLoadEnumMembers),
                            null);
                    }
                    else
                    {
                        Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) =>
                        {
                            // Create properties without modifying the complexType.
                            // This will leave complexType intact in case of an exception during loading.
                            List <IEdmProperty> loadedProperties = new List <IEdmProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property);
                                loadedProperties.Add(edmProperty);
                            }

                            // Now add properties to the complexType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                complexType.AddProperty(property);
                            }
                        };

                        // Creating a complex type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), isOpen, delayLoadComplexProperties),
                            hasProperties);
                    }
                }

                Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

                IEdmType             edmType = cachedEdmType.EdmType;
                ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                this.SetClientTypeAnnotation(edmType, clientTypeAnnotation);

                if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    Debug.Assert(edmStructuredType != null, "edmStructuredType != null");
                    this.SetMimeTypeForProperties(edmStructuredType);
                }

                // Need to cache the type before loading the properties so we don't stack overflow because
                // loading the property can trigger calls to GetOrCreateEdmType on the same type.
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue existing;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out existing))
                    {
                        cachedEdmType = existing;
                    }
                    else
                    {
                        this.clrToEdmTypeCache.Add(type, cachedEdmType);
                    }
                }
            }

            return(cachedEdmType);
        }
示例#3
0
        /// <summary>
        /// Binds 'cast' function to create a LINQ <see cref="Expression"/>.
        /// </summary>
        /// <param name="node">The query node to bind.</param>
        /// <param name="context">The query binder context.</param>
        /// <returns>The LINQ <see cref="Expression"/> created.</returns>
        protected virtual Expression BindCastSingleValue(SingleValueFunctionCallNode node, QueryBinderContext context)
        {
            CheckArgumentNull(node, context, "cast");

            Expression[] arguments = BindArguments(node.Parameters, context);
            Contract.Assert(arguments.Length == 1 || arguments.Length == 2);

            Expression source         = arguments.Length == 1 ? context.CurrentParameter : arguments[0];
            string     targetTypeName = (string)((ConstantNode)node.Parameters.Last()).Value;
            IEdmType   targetEdmType  = context.Model.FindType(targetTypeName);
            Type       targetClrType  = null;

            if (targetEdmType != null)
            {
                IEdmTypeReference targetEdmTypeReference = targetEdmType.ToEdmTypeReference(false);
                targetClrType = context.Model.GetClrType(targetEdmTypeReference);

                if (source != NullConstant)
                {
                    if (source.Type == targetClrType)
                    {
                        return(source);
                    }

                    if ((!targetEdmTypeReference.IsPrimitive() && !targetEdmTypeReference.IsEnum()) ||
                        (context.Model.GetEdmPrimitiveTypeReference(source.Type) == null && !TypeHelper.IsEnum(source.Type)))
                    {
                        // Cast fails and return null.
                        return(NullConstant);
                    }
                }
            }

            if (targetClrType == null || source == NullConstant)
            {
                return(NullConstant);
            }

            if (targetClrType == typeof(string))
            {
                return(ExpressionBinderHelper.BindCastToStringType(source));
            }
            else if (TypeHelper.IsEnum(targetClrType))
            {
                return(BindCastToEnumType(source.Type, targetClrType, node.Parameters.First(), arguments.Length, context));
            }
            else
            {
                if (TypeHelper.IsNullable(source.Type) && !TypeHelper.IsNullable(targetClrType))
                {
                    // Make the target Clr type nullable to avoid failure while casting
                    // nullable source, whose value may be null, to a non-nullable type.
                    // For example: cast(NullableInt32Property,Edm.Int64)
                    // The target Clr type should be Nullable<Int64> rather than Int64.
                    targetClrType = typeof(Nullable <>).MakeGenericType(targetClrType);
                }

                try
                {
                    return(Expression.Convert(source, targetClrType));
                }
                catch (InvalidOperationException)
                {
                    // Cast fails and return null.
                    return(NullConstant);
                }
            }
        }