internal override Expression VisitUnary(UnaryExpression u)
            {
                Debug.Assert(u != null, "u != null");

                // Perfectly assignable conversions are OK. VB.NET compilers
                // inserts these to exactly match method signatures, for example.
                if (ResourceBinder.PatternRules.MatchConvertToAssignable(u) || (u.NodeType == ExpressionType.TypeAs && this.leafExpressionIsMemberAccess))
                {
                    return(base.VisitUnary(u));
                }

                if ((u.NodeType == ExpressionType.Convert) || (u.NodeType == ExpressionType.ConvertChecked))
                {
                    Type sourceType = Nullable.GetUnderlyingType(u.Operand.Type) ?? u.Operand.Type;
                    Type targetType = Nullable.GetUnderlyingType(u.Type) ?? u.Type;

                    // when projecting known entity types, will allow convert expressions of primitive types.
                    if (PrimitiveType.IsKnownType(sourceType) && PrimitiveType.IsKnownType(targetType))
                    {
                        return(base.Visit(u.Operand));
                    }
                }

                // In V3 while we support TypeAs conversions, we only support TypeAs before a MemberAccess and not TypeAs as the last operation
                // i.e. we support "Manager = (p as Employee).Manager" (see VisitMemberAccess for detail), but we dont support "Manager = (p as Manager)"
                // Note that the server also doesn't support a property path which ends with a type identifier.
                throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, u.ToString()));
            }
Example #2
0
        /// <summary>
        /// Returns the primitive property value.
        /// </summary>
        /// <param name="propertyValue">Value of the property.</param>
        /// <param name="propertyType">Type of the property.</param>
        /// <returns>Returns the value of the primitive property.</returns>
        internal static object ConvertPrimitiveValueToRecognizedODataType(object propertyValue, Type propertyType)
        {
            Debug.Assert(PrimitiveType.IsKnownNullableType(propertyType), "GetPrimitiveValue must be called only for primitive types");
            Debug.Assert(propertyValue == null || PrimitiveType.IsKnownType(propertyValue.GetType()), "GetPrimitiveValue method must be called for primitive values only");

            if (propertyValue == null)
            {
                return(null);
            }

            PrimitiveType primitiveType;

            PrimitiveType.TryGetPrimitiveType(propertyType, out primitiveType);
            Debug.Assert(primitiveType != null, "must be a known primitive type");

            // Do the conversion for types that are not supported by ODataLib e.g. char[], char, etc
            if (propertyType == typeof(Char) ||
                propertyType == typeof(Char[]) ||
                propertyType == typeof(Type) ||
                propertyType == typeof(Uri) ||
                propertyType == typeof(System.Xml.Linq.XDocument) ||
                propertyType == typeof(System.Xml.Linq.XElement))
            {
                return(primitiveType.TypeConverter.ToString(propertyValue));
            }
            else if (propertyType == typeof(DateTime))
            {
                return(PlatformHelper.ConvertDateTimeToDateTimeOffset((DateTime)propertyValue));
            }
#if !PORTABLELIB
            else if (propertyType.FullName == "System.Data.Linq.Binary")
            {
                // For System.Data.Linq.Binary, it is a delay loaded type. Hence checking it based on name.
                // PrimitiveType.IsKnownType checks for binary type based on name and assembly. Hence just
                // checking name here is sufficient, since any other type with the same name, but in different
                // assembly will return false for PrimitiveType.IsKnownNullableType.
                // Since ODataLib does not understand binary type, we need to convert the value to byte[].
                return(((BinaryTypeConverter)primitiveType.TypeConverter).ToArray(propertyValue));
            }
#endif
            else if (primitiveType.EdmTypeName == null)
            {
                // case StorageType.DateTimeOffset:
                // case StorageType.TimeSpan:
                // case StorageType.UInt16:
                // case StorageType.UInt32:
                // case StorageType.UInt64:
                // don't support reverse mappings for these types in this version
                // allows us to add real server support in the future without a
                // "breaking change" in the future client
                throw new NotSupportedException(Strings.ALinq_CantCastToUnsupportedPrimitive(propertyType.Name));
            }

            return(propertyValue);
        }
        /// <summary>The QueryComponents associated with this request</summary>
        /// <param name="model">The client model.</param>
        /// <returns>an instance of QueryComponents.</returns>
        internal override QueryComponents QueryComponents(ClientEdmModel model)
        {
            if (this.queryComponents == null)
            {
                Type elementType = typeof(TElement);

                // for 1..* navigation properties we need the type of the entity of the collection that is being navigated to. Otherwise we use TElement.
                elementType          = PrimitiveType.IsKnownType(elementType) || WebUtil.IsCLRTypeCollection(elementType, model) ? elementType : TypeSystem.GetElementType(elementType);
                this.queryComponents = new QueryComponents(this.requestUri, Util.ODataVersionEmpty, elementType, null, null);
            }

            return(this.queryComponents);
        }
Example #4
0
        /// <summary>
        /// Resolves the client type that should be used for materialization.
        /// </summary>
        /// <param name="expectedType">Expected client clr type based on the API called.</param>
        /// <param name="readerTypeName">
        /// The name surfaced by the ODataLib reader.
        /// If we have a server model, this will be a server type name that needs to be resolved.
        /// If not, then this will already be a client type name.</param>
        /// <returns>The resolved annotation for the client type to materialize into.</returns>
        internal ClientTypeAnnotation ResolveTypeForMaterialization(Type expectedType, string readerTypeName)
        {
            // If its a collection, get the collection item name
            string collectionItemTypeName = WebUtil.GetCollectionItemWireTypeName(readerTypeName);

            if (collectionItemTypeName == null)
            {
                // Resolve the primitive type first
                PrimitiveType primitiveType;
                if (PrimitiveType.TryGetPrimitiveType(readerTypeName, out primitiveType))
                {
                    return(this.clientEdmModel.GetClientTypeAnnotation(primitiveType.ClrType));
                }

                ClientTypeAnnotation resultType;
                if (this.edmTypeNameMap.TryGetValue(readerTypeName, out resultType))
                {
                    return(resultType);
                }

                if (this.serviceModel != null)
                {
                    var resolvedType = this.ResolveTypeFromName(readerTypeName, expectedType);
                    return(this.clientEdmModel.GetClientTypeAnnotation(resolvedType));
                }

                // If there was no type name specified in the payload, then the type resolver won't be invoked
                // and hence that edm type name might not be in the resolver cache. Hence look that up in the
                // ClientEdmModel cache. This lookup is more expensive and is unique across the app domain for the
                // given version.
                return(this.clientEdmModel.GetClientTypeAnnotation(readerTypeName));
            }

            Type collectionImplementationType = ClientTypeUtil.GetImplementationType(expectedType, typeof(ICollection <>));
            Type collectionElementType        = collectionImplementationType.GetGenericArguments()[0];

            // In case of collection, the expectedType might be collection of nullable types (for e.g. ICollection<int?>).
            // There is no way to know the nullability from the wireTypeName (For e.g. Collection(Edm.Int32)).
            // Hence in case of collections of primitives, we need to look at the element type of the expected type
            // and use that to create the instance otherwise we will not be able to assign the created ICollection<>
            // instance to the property on the user's entity (ICollection<int> cannot be assigned to ICollection<int?>).
            // There is also no need to invoke the resolver for primitives, so we just use the element type.
            if (!PrimitiveType.IsKnownType(collectionElementType))
            {
                collectionElementType = this.ResolveTypeForMaterialization(collectionElementType, collectionItemTypeName).ElementType;
            }

            Type clrCollectionType = WebUtil.GetBackingTypeForCollectionProperty(expectedType);

            return(this.clientEdmModel.GetClientTypeAnnotation(clrCollectionType));
        }