예제 #1
0
 SortArgument GetSortArgumentFromSortCall(MethodCallExpression node)
 {
     if (node.Arguments[1].NodeType == ExpressionType.Quote)
     {
         UnaryExpression quote = (UnaryExpression)node.Arguments[1];
         if (quote.Operand.NodeType == ExpressionType.Lambda)
         {
             LambdaExpression lambda = (LambdaExpression)quote.Operand;
             if (lambda.Parameters.Count == 1)
             {
                 SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]);
                 Expression             imported = importer.Import(lambda.Body);
                 if (imported != null)
                 {
                     return(new SortArgument(
                                Expression.Lambda(imported, lambda.Parameters[0]),
                                IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc) ||
                                IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_ThenByDesc)
                                ));
                 }
             }
         }
     }
     return(null);
 }
			SortArgument GetSortArgumentFromSortCall(MethodCallExpression node)
			{
				if (node.Arguments[1].NodeType == ExpressionType.Quote) {
					UnaryExpression quote = (UnaryExpression)node.Arguments[1];
					if (quote.Operand.NodeType == ExpressionType.Lambda) {
						LambdaExpression lambda = (LambdaExpression)quote.Operand;
						if (lambda.Parameters.Count == 1) {
							SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]);
							Expression imported = importer.Import(lambda.Body);
							if (imported != null)
								return new SortArgument(
									Expression.Lambda(imported, lambda.Parameters[0]),
									IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc)
									|| IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_ThenByDesc)
								);
						}
					}
				}
				return null;
			}
예제 #3
0
            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote)
                {
                    // CallTreeNode[].Select:
                    // selects are not supported by query evaluator, but we will detect and remove
                    // degenerate selects (.Select(x => x)).
                    UnaryExpression quote = (UnaryExpression)node.Arguments[1];
                    if (quote.Operand.NodeType == ExpressionType.Lambda)
                    {
                        LambdaExpression lambda = (LambdaExpression)quote.Operand;
                        if (lambda.Parameters.Count == 1 && lambda.Body == lambda.Parameters[0])
                        {
                            return(Visit(node.Arguments[0]));
                        }
                    }
                }
                else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Where && node.Arguments[1].NodeType == ExpressionType.Quote)
                {
                    // CallTreeNode[].Where:
                    // if the target is a QueryNode and the condition can be safely imported, convert the Where call to Filter
                    UnaryExpression quote = (UnaryExpression)node.Arguments[1];
                    if (quote.Operand.NodeType == ExpressionType.Lambda)
                    {
                        LambdaExpression lambda = (LambdaExpression)quote.Operand;
                        if (lambda.Parameters.Count == 1)
                        {
                            QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                            if (target != null)
                            {
                                SafeExpressionImporter  importer   = new SafeExpressionImporter(lambda.Parameters[0]);
                                List <LambdaExpression> conditions = new List <LambdaExpression>();
                                if (importer.AddConditionsToFilterList(lambda.Body, conditions))
                                {
                                    return(new Filter(target, conditions.ToArray()));
                                }
                            }
                        }
                    }
                }
                else if (node.Method == KnownMembers.Queryable_WithQueryLog && node.Arguments[1].NodeType == ExpressionType.Constant)
                {
                    options.AddLogger((TextWriter)(((ConstantExpression)node.Arguments[1]).Value));
                    return(Visit(node.Arguments[0]));
                }
                else if (node.Method == KnownMembers.Queryable_MergeByName)
                {
                    QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                    if (target != null)
                    {
                        return(new MergeByName(target));
                    }
                }
                else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Take && node.Arguments[1].NodeType == ExpressionType.Constant)
                {
                    ConstantExpression ce = (ConstantExpression)node.Arguments[1];
                    if (ce.Type == typeof(int))
                    {
                        QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                        if (target != null)
                        {
                            return(new Limit(target, 0, (int)ce.Value));
                        }
                    }
                }
                else if (IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderBy) ||
                         IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc))
                {
                    SortArgument sortArgument = GetSortArgumentFromSortCall(node);
                    if (sortArgument != null)
                    {
                        QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                        if (target != null)
                        {
                            return(new Sort(target, new [] { sortArgument }));
                        }
                    }
                }
                else if (IsThenByCall(node))
                {
                    // 'ThenBy' is dangerous: we must not translate an OrderBy inside a ThenBy that we do not support
                    List <MethodCallExpression> thenByCalls = new List <MethodCallExpression>();
                    Expression tmp = node;
                    while (IsThenByCall(tmp))
                    {
                        thenByCalls.Add((MethodCallExpression)tmp);
                        tmp = ((MethodCallExpression)tmp).Arguments[0];
                    }
                    MethodCallExpression mc = tmp as MethodCallExpression;
                    if (mc != null &&
                        (IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderBy) ||
                         IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderByDesc)))
                    {
                        // TODO: add support for safe expressions in ThenBy

                        // this is an unsupported OrderBy/ThenBy sequence
                        // skip visiting the sequence and go directly into the base object
                        tmp = Visit(mc.Arguments[0]);
                        // now reconstruct the OrderBy/ThenBy sequence
                        tmp = Expression.Call(mc.Method, new[] { tmp }.Concat(mc.Arguments.Skip(1)));                         // reconstruct OrderBy
                        for (int i = thenByCalls.Count - 1; i >= 0; i--)
                        {
                            // reconstruct ThenBy
                            tmp = Expression.Call(thenByCalls[i].Method, new[] { tmp }.Concat(thenByCalls[i].Arguments.Skip(1)));
                        }
                        return(tmp);
                    }
                    // else: we couldn't detect the OrderBy belonging to this ThenBy; so it's probably not one
                    // of the OrderBy overloads that we support. Go down recursively
                }
                return(base.VisitMethodCall(node));
            }
			protected override Expression VisitMethodCall(MethodCallExpression node)
			{
				if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote) {
					// CallTreeNode[].Select:
					// selects are not supported by query evaluator, but we will detect and remove
					// degenerate selects (.Select(x => x)).
					UnaryExpression quote = (UnaryExpression)node.Arguments[1];
					if (quote.Operand.NodeType == ExpressionType.Lambda) {
						LambdaExpression lambda = (LambdaExpression)quote.Operand;
						if (lambda.Parameters.Count == 1 && lambda.Body == lambda.Parameters[0])
							return Visit(node.Arguments[0]);
					}
				} else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Where && node.Arguments[1].NodeType == ExpressionType.Quote) {
					// CallTreeNode[].Where:
					// if the target is a QueryNode and the condition can be safely imported, convert the Where call to Filter
					UnaryExpression quote = (UnaryExpression)node.Arguments[1];
					if (quote.Operand.NodeType == ExpressionType.Lambda) {
						LambdaExpression lambda = (LambdaExpression)quote.Operand;
						if (lambda.Parameters.Count == 1) {
							QueryNode target = Visit(node.Arguments[0]) as QueryNode;
							if (target != null) {
								SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]);
								List<LambdaExpression> conditions = new List<LambdaExpression>();
								if (importer.AddConditionsToFilterList(lambda.Body, conditions)) {
									return new Filter(target, conditions.ToArray());
								}
							}
						}
					}
				} else if (node.Method == KnownMembers.Queryable_WithQueryLog && node.Arguments[1].NodeType == ExpressionType.Constant) {
					options.AddLogger((TextWriter)(((ConstantExpression)node.Arguments[1]).Value));
					return Visit(node.Arguments[0]);
				} else if (node.Method == KnownMembers.Queryable_MergeByName) {
					QueryNode target = Visit(node.Arguments[0]) as QueryNode;
					if (target != null)
						return new MergeByName(target);
				} else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Take && node.Arguments[1].NodeType == ExpressionType.Constant) {
					ConstantExpression ce = (ConstantExpression)node.Arguments[1];
					if (ce.Type == typeof(int)) {
						QueryNode target = Visit(node.Arguments[0]) as QueryNode;
						if (target != null) {
							return new Limit(target, 0, (int)ce.Value);
						}
					}
				} else if (IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderBy) ||
				           IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc)) {
					SortArgument sortArgument = GetSortArgumentFromSortCall(node);
					if (sortArgument != null) {
						QueryNode target = Visit(node.Arguments[0]) as QueryNode;
						if (target != null) {
							return new Sort(target, new [] { sortArgument });
						}
					}
				} else if (IsThenByCall(node)) {
					// 'ThenBy' is dangerous: we must not translate an OrderBy inside a ThenBy that we do not support
					List<MethodCallExpression> thenByCalls = new List<MethodCallExpression>();
					Expression tmp = node;
					while (IsThenByCall(tmp)) {
						thenByCalls.Add((MethodCallExpression)tmp);
						tmp = ((MethodCallExpression)tmp).Arguments[0];
					}
					MethodCallExpression mc = tmp as MethodCallExpression;
					if (mc != null &&
					    (IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderBy) ||
					     IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderByDesc)))
					{
						// TODO: add support for safe expressions in ThenBy
						
						// this is an unsupported OrderBy/ThenBy sequence
						// skip visiting the sequence and go directly into the base object
						tmp = Visit(mc.Arguments[0]);
						// now reconstruct the OrderBy/ThenBy sequence
						tmp = Expression.Call(mc.Method, new[] { tmp }.Concat(mc.Arguments.Skip(1))); // reconstruct OrderBy
						for (int i = thenByCalls.Count - 1; i >= 0; i--) {
							// reconstruct ThenBy
							tmp = Expression.Call(thenByCalls[i].Method, new[] { tmp }.Concat(thenByCalls[i].Arguments.Skip(1)));
						}
						return tmp;
					}
					// else: we couldn't detect the OrderBy belonging to this ThenBy; so it's probably not one
					// of the OrderBy overloads that we support. Go down recursively
				}
				return base.VisitMethodCall(node);
			}