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())); }
internal override System.Data.Services.Client.QueryComponents QueryComponents(DataServiceProtocolVersion maxProtocolVersion) { if (this.queryComponents == null) { Type type = typeof(TElement); type = (PrimitiveType.IsKnownType(type) || WebUtil.IsCLRTypeCollection(type, maxProtocolVersion)) ? type : TypeSystem.GetElementType(type); this.queryComponents = new System.Data.Services.Client.QueryComponents(this.requestUri, Util.DataServiceVersionEmpty, type, null, null); } return(this.queryComponents); }
/// <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.DataServiceVersionEmpty, elementType, null, null); } return(this.queryComponents); }
/// <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> private 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(Xml.Linq.XDocument) || propertyType == typeof(Xml.Linq.XElement)) { return(primitiveType.TypeConverter.ToString(propertyValue)); } #if !ASTORIA_LIGHT && !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> /// 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, collectionElementType); return(this.clientEdmModel.GetClientTypeAnnotation(clrCollectionType)); }
internal override Expression VisitUnary(UnaryExpression u) { 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 type = Nullable.GetUnderlyingType(u.Operand.Type) ?? u.Operand.Type; Type type2 = Nullable.GetUnderlyingType(u.Type) ?? u.Type; if (PrimitiveType.IsKnownType(type) && PrimitiveType.IsKnownType(type2)) { return(base.Visit(u.Operand)); } } throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, u.ToString())); }