/// <summary> /// Analyzes the specified <paramref name="lambda"/> for selection and updates /// <paramref name="resource"/>. /// </summary> /// <param name="lambda">Lambda expression to analyze.</param> /// <param name="resource">Resource expression to update.</param> /// <param name="context">Context of expression to analyze.</param> private static void AnalyzeResourceExpression(LambdaExpression lambda, ResourceExpression resource, DataServiceContext context) { SelectExpandPathBuilder pb = new SelectExpandPathBuilder(); ProjectionAnalyzer.Analyze(lambda, pb, context); resource.Projection = new ProjectionQueryOptionExpression(lambda.Body.Type, lambda, pb.ProjectionPaths.ToList()); resource.ExpandPaths = pb.ExpandPaths.Union(resource.ExpandPaths, StringComparer.Ordinal).ToList(); resource.RaiseUriVersion(pb.UriVersion); }
internal override Expression VisitMemberInit(MemberInitExpression init) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(init.Type)) { // MemberInit to a complex type is not supported on entity types. throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, init.ToString())); } ProjectionAnalyzer.Analyze(init, this.builder, this.context); return(init); }
internal override Expression VisitMethodCall(MethodCallExpression m) { // We throw NotSupportedException when IsDisallowedExceptionForMethodCall() is true // or we have a method call on a non-entity type, for example c.MyCollectionComplexProperty.Select(...) if ((m.Object != null && (IsDisallowedExpressionForMethodCall(m.Object, this.context.Model) || !ClientTypeUtil.TypeOrElementTypeIsEntity(m.Object.Type))) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a, this.context.Model)) || (m.Object == null && !ClientTypeUtil.TypeOrElementTypeIsEntity(m.Arguments[0].Type))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { CheckChainedSequence(m, this.type); // allow selects for following pattern: // Orders = c.Orders.Select(o=> new NarrowOrder {...}).ToList(); return(base.VisitMethodCall(m)); } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
internal override Expression VisitMethodCall(MethodCallExpression m) { if ((m.Object != null && IsDisallowedExpressionForMethodCall(m.Object, this.context.Model)) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a, this.context.Model))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } CheckChainedSequence(m, this.type); if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { // allow IEnum.Select and IEnum.ToList even if entity type. return(base.VisitMethodCall(m)); } if ((m.Object != null ? ClientTypeUtil.TypeOrElementTypeIsEntity(m.Object.Type) : false) || m.Arguments.Any(a => ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } return(base.VisitMethodCall(m)); }
internal override Expression VisitMemberInit(MemberInitExpression init) { ProjectionAnalyzer.Analyze(init, this.builder, this.context); return(init); }
internal override Expression VisitLambda(LambdaExpression lambda) { ProjectionAnalyzer.Analyze(lambda, this.builder, this.context); return(lambda); }
/// <summary> /// CODE: x /// ORIGINAL: Convert(x, t) where t is assignable from typeof(x) /// ORIGINAL: x as t, where t is assignable from typeof(x) /// ORIGINAL: and typeof(x) or t are not known primitives unless typeof(x) == t /// ORIGINAL: and x is not a collection of entity types /// ORIGINAL: and x is not a enum type /// NORMALIZED: x /// </summary> internal override Expression VisitUnary(UnaryExpression u) { UnaryExpression visited = (UnaryExpression)base.VisitUnary(u); Expression result = visited; // Note that typically we would record a potential rewrite // after extracting the conversion, but we avoid doing this // because it breaks undoing the rewrite by making the non-local // change circular, ie: // unary [operand = a] // becomes // a <- unary [operand = a] // So the undoing visits a, then the original unary, then the // operand and again the unary, the operand, etc. this.RecordRewrite(u, result); // Convert(x, t) or x as t, where t is assignable from typeof(x) if ((visited.NodeType == ExpressionType.Convert || visited.NodeType == ExpressionType.TypeAs) && visited.Type.IsAssignableFrom(visited.Operand.Type)) { // typeof(x) or t are not known primitives unless typeof(x) == t if (!PrimitiveType.IsKnownNullableType(visited.Operand.Type) && !PrimitiveType.IsKnownNullableType(visited.Type) || visited.Operand.Type == visited.Type) { // x is not a collection of entity types if (!(ClientTypeUtil.TypeOrElementTypeIsEntity(visited.Operand.Type) && ProjectionAnalyzer.IsCollectionProducingExpression(visited.Operand))) { // x is not an enum type if (!visited.Operand.Type.IsEnum()) { result = visited.Operand; } } } } return(result); }