2011-11-27 19 views
6

Tôi đang cố gắng hiểu rõ các biểu thức. Tôi đang nhấn tham số "sợ hãi" không bị ràng buộc trong biểu thức truy vấn LINQ to Entities được chỉ định "ngoại lệ. Tôi đã thấy Skeet trả lời câu hỏi này trước cũng như những người khác trực tuyến. Tuy nhiên tôi chỉ không thể "nhìn thấy" vấn đề. Tôi đang sử dụng ví dụ của Colin Meek http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx và lớp VisitorExpression của Matt Warren http://blogs.msdn.com/b/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx. Tôi đang sử dụng một ứng dụng giao diện điều khiển trong VS 2010, khung 4.0. Xin lỗi nếu điều này là đánh bại một con ngựa chết vì nó đã được hỏi về trước. Cảm ơn vì bất kì sự giúp đỡ.Tham số "sợ hãi" không bị ràng buộc trong biểu thức truy vấn LINQ to Entities được chỉ định "ngoại lệ

Để được triệt để, tất cả các mã dưới:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red"; 
     Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0; 
     Expression<Func<Car, bool>> theCarIsRedOrCheap = theCarIsRed.Or(theCarIsCheap); 

     Car one = new Car() { CarId = 1, Color = "Red", Price = 10.0 }; 
     Car two = new Car() { CarId = 2, Color = "Blue", Price = 9.0 }; 
     Car three = new Car() { CarId = 3, Color = "Black", Price = 5.0 }; 
     Car four = new Car() { CarId = 4, Color = "Red", Price = 5.0 }; 

     EntityDBContext context = new EntityDBContext(); 
     context.CarEntity.Add(one); 
     context.CarEntity.Add(two); 
     context.CarEntity.Add(three); 
     context.CarEntity.Add(four); 

     using (var db = context) 
     { 
      // Bang 
      var query = db.CarEntity.AsQueryable().Where(theCarIsRedOrCheap).ToList(); 

      foreach (var item in query) 
      { 
       Console.WriteLine(item.Color, item.Price); 
      } 
     } 

     Console.ReadKey(); 
    } 
} 

public class Car 
{ 
    [Key] 
    public int CarId { get; set; } 
    public string Color { get; set; } 
    public double Price { get; set; } 
} 


public static class Utility 
{ 
    public static Expression<T> Compose<T>(this Expression<T> first, 
     Expression<T> second, Func<Expression, Expression, Expression> merge) 
    { 
     var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); 

     var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); 

     return Expression.Lambda<T>(merge(first.Body, second.Body), first.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) 
    { 
     return first.Compose(second, Expression.And); 
    } 

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) 
    { 
     return first.Compose(second, Expression.Or); 
    } 
} 


public class ParameterRebinder : ExpressionVisitor 
{ 
    private readonly Dictionary<ParameterExpression, ParameterExpression> map; 

    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) 
    { 
     this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); 
    } 

    public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) 
    { 
     return new ParameterRebinder(map).Visit(exp); 
    } 

    protected override Expression VisitParameter(ParameterExpression parmEx) 
    { 
     ParameterExpression replacement; 
     if (map.TryGetValue(parmEx, out replacement)) 
     { 
      parmEx = replacement; 
     } 

     return base.VisitParameter(parmEx); 
    } 
} 

public abstract class ExpressionVisitor 
{ 
    protected ExpressionVisitor() 
    { 
    } 

    protected virtual Expression Visit(Expression exp) 
    { 
     if (exp == null) 
     { 
      return exp; 
     } 

     switch (exp.NodeType) 
     { 
      case ExpressionType.Negate: 
      case ExpressionType.NegateChecked: 
      case ExpressionType.Not: 
      case ExpressionType.Convert: 
      case ExpressionType.ConvertChecked: 
      case ExpressionType.ArrayLength: 
      case ExpressionType.Quote: 
      case ExpressionType.TypeAs: 
       return this.VisitUnary((UnaryExpression) exp); 
      case ExpressionType.Add: 
      case ExpressionType.AddChecked: 
      case ExpressionType.Subtract: 
      case ExpressionType.SubtractChecked: 
      case ExpressionType.Multiply: 
      case ExpressionType.MultiplyChecked: 
      case ExpressionType.Divide: 
      case ExpressionType.Modulo: 
      case ExpressionType.And: 
      case ExpressionType.AndAlso: 
      case ExpressionType.Or: 
      case ExpressionType.OrElse: 
      case ExpressionType.LessThan: 
      case ExpressionType.LessThanOrEqual: 
      case ExpressionType.GreaterThan: 
      case ExpressionType.GreaterThanOrEqual: 
      case ExpressionType.Equal: 
      case ExpressionType.NotEqual: 
      case ExpressionType.Coalesce: 
      case ExpressionType.ArrayIndex: 
      case ExpressionType.RightShift: 
      case ExpressionType.LeftShift: 
      case ExpressionType.ExclusiveOr: 
       return this.VisitBinary((BinaryExpression) exp); 
      case ExpressionType.TypeIs: 
       return this.VisitTypeIs((TypeBinaryExpression) exp); 
      case ExpressionType.Conditional: 
       return this.VisitConditional((ConditionalExpression) exp); 
      case ExpressionType.Constant: 
       return this.VisitConstant((ConstantExpression) exp); 
      case ExpressionType.Parameter: 
       return this.VisitParameter((ParameterExpression) exp); 
      case ExpressionType.MemberAccess: 
       return this.VisitMemberAccess((MemberExpression) exp); 
      case ExpressionType.Call: 
       return this.VisitMethodCall((MethodCallExpression) exp); 
      case ExpressionType.Lambda: 
       return this.VisitLambda((LambdaExpression) exp); 
      case ExpressionType.New: 
       return this.VisitNew((NewExpression) exp); 
      case ExpressionType.NewArrayInit: 
      case ExpressionType.NewArrayBounds: 
       return this.VisitNewArray((NewArrayExpression) exp); 
      case ExpressionType.Invoke: 
       return this.VisitInvocation((InvocationExpression) exp); 
      case ExpressionType.MemberInit: 
       return this.VisitMemberInit((MemberInitExpression) exp); 
      case ExpressionType.ListInit: 
       return this.VisitListInit((ListInitExpression) exp); 
      default: 
       throw new Exception(String.Format("Unhandled expression type: '{0}'", exp.NodeType)); 

     } 
    } 

    protected virtual MemberBinding VisitBinding(MemberBinding binding) 
    { 
     switch (binding.BindingType) 
     { 
      case MemberBindingType.Assignment: 
       return this.VisitMemberAssignment((MemberAssignment) binding); 
       case MemberBindingType.MemberBinding: 
       return this.VisitMemberMemberBinding((MemberMemberBinding) binding); 
       case MemberBindingType.ListBinding: 
       return this.VisitMemberListBinding((MemberListBinding) binding); 
      default: 
       throw new Exception(String.Format("Unhandled binding type '{0}'", binding.BindingType)); 
     } 
    } 

    protected virtual Expression VisitListInit(ListInitExpression init) 
    { 
     NewExpression n = this.VisitNew(init.NewExpression); 
     IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(init.Initializers); 

     if (n != init.NewExpression || initializers != init.Initializers) 
     { 
      return Expression.ListInit(n, initializers); 
     } 

     return init; 
    } 

    protected virtual Expression VisitMemberInit(MemberInitExpression memberInitExpression) 
    { 
     NewExpression n = this.VisitNew(memberInitExpression.NewExpression); 
     IEnumerable<MemberBinding> bindings = this.VisitBindingList(memberInitExpression.Bindings); 

     if (n != memberInitExpression.NewExpression || bindings != memberInitExpression.Bindings) 
     { 
      return Expression.MemberInit(n, bindings); 
     } 

     return memberInitExpression; 
    } 

    protected virtual Expression VisitInvocation(InvocationExpression invocationExpression) 
    { 
     IEnumerable<Expression> args = this.VisitExpressionList(invocationExpression.Arguments); 
     Expression expr = this.Visit(invocationExpression.Expression); 

     if (args != invocationExpression.Arguments || expr != invocationExpression.Expression) 
     { 
      return Expression.Invoke(expr, args); 
     } 

     return invocationExpression; 
    } 

    protected virtual Expression VisitNewArray(NewArrayExpression newArrayExpression) 
    { 
     IEnumerable<Expression> exprs = this.VisitExpressionList(newArrayExpression.Expressions); 

     if (exprs != newArrayExpression.Expressions) 
     { 
      if (newArrayExpression.NodeType == ExpressionType.NewArrayInit) 
      { 
       return Expression.NewArrayInit(newArrayExpression.Type.GetElementType(), exprs); 
      } 
      else 
      { 
       return Expression.NewArrayBounds(newArrayExpression.Type.GetElementType()); 
      } 
     } 

     return newArrayExpression; 
    } 

    protected virtual NewExpression VisitNew(NewExpression newExpression) 
    { 
     IEnumerable<Expression> args = this.VisitExpressionList(newExpression.Arguments); 

     if (args != newExpression.Arguments) 
     { 
      if (newExpression.Members != null) 
      { 
       return Expression.New(newExpression.Constructor, args, newExpression.Members); 
      } 
      else 
      { 
       return Expression.New(newExpression.Constructor, args); 
      } 
     } 

     return newExpression; 
    } 

    protected virtual Expression VisitLambda(LambdaExpression lambdaExpression) 
    { 
     Expression body = this.Visit(lambdaExpression.Body); 
     if (body != lambdaExpression.Body) 
     { 
      return Expression.Lambda(lambdaExpression.Type, body, lambdaExpression.Parameters); 
     } 

     return lambdaExpression; 
    } 

    protected virtual Expression VisitMethodCall(MethodCallExpression methodCallExpression) 
    { 
     Expression obj = this.Visit(methodCallExpression.Object); 
     IEnumerable<Expression> args = this.VisitExpressionList(methodCallExpression.Arguments); 

     if (obj != methodCallExpression.Object || args != methodCallExpression.Arguments) 
     { 
      return Expression.Call(obj, methodCallExpression.Method, args); 
     } 

     return methodCallExpression; 
    } 

    protected virtual Expression VisitMemberAccess(MemberExpression memberExpression) 
    { 
     Expression exp = this.Visit(memberExpression.Expression); 

     if (exp != memberExpression.Expression) 
     { 
      return Expression.MakeMemberAccess(exp, memberExpression.Member); 
     } 

     return memberExpression; 
    } 

    protected virtual Expression VisitParameter(ParameterExpression parameterExpression) 
    { 
     return parameterExpression; 
    } 

    protected virtual Expression VisitConstant(ConstantExpression constantExpression) 
    { 
     return constantExpression; 
    } 

    protected virtual Expression VisitConditional(ConditionalExpression conditionalExpression) 
    { 
     Expression test = this.Visit(conditionalExpression.Test); 
     Expression ifTrue = this.Visit(conditionalExpression.IfTrue); 
     Expression ifFalse = this.Visit(conditionalExpression.IfFalse); 

     if (test != conditionalExpression.Test || ifTrue != conditionalExpression.IfTrue || ifFalse != conditionalExpression.IfFalse) 
     { 
      return Expression.Condition(test, ifTrue, ifFalse); 
     } 

     return conditionalExpression; 
    } 

    protected virtual Expression VisitTypeIs(TypeBinaryExpression typeBinaryExpression) 
    { 
     Expression expr = this.Visit(typeBinaryExpression.Expression); 
     if (expr != typeBinaryExpression) 
     { 
      return Expression.TypeIs(expr, typeBinaryExpression.TypeOperand); 
     } 

     return typeBinaryExpression; 
    } 

    protected virtual Expression VisitBinary(BinaryExpression binaryExpression) 
    { 
     Expression left = this.Visit(binaryExpression.Left); 
     Expression right = this.Visit(binaryExpression.Right); 
     Expression conversion = this.Visit(binaryExpression.Conversion); 

     if (left != binaryExpression.Left || right != binaryExpression.Right || conversion != binaryExpression.Conversion) 
     { 
      if (binaryExpression.NodeType == ExpressionType.Coalesce && binaryExpression.Conversion != null) 
      { 
       return Expression.Coalesce(left, right, conversion as LambdaExpression); 
      } 
      else 
      { 
       return Expression.MakeBinary(binaryExpression.NodeType, left, right, binaryExpression.IsLiftedToNull, 
              binaryExpression.Method); 
      } 
     } 

     return binaryExpression; 
    } 

    protected virtual Expression VisitUnary(UnaryExpression unaryExpression) 
    { 
     Expression operand = this.Visit(unaryExpression.Operand); 
     if (operand != unaryExpression.Operand) 
     { 
      return Expression.MakeUnary(unaryExpression.NodeType, operand, unaryExpression.Type, 
             unaryExpression.Method); 
     } 

     return unaryExpression; 
    } 

    protected virtual ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCollection<Expression> original) 
    { 
     List<Expression> list = null; 

     for (int i = 0, n = original.Count; i < n; i++) 
     { 
      Expression p = this.Visit(original[i]); 
      if (list != null) 
      { 
       list.Add(p); 
      } 
      else if (p != original[i]) 
      { 
       list = new List<Expression>(n); 
       for (int j = 0; j < i; j++) 
       { 
        list.Add(original[j]); 
       } 

       list.Add(p); 
      } 
     } 

     return list != null ? list.AsReadOnly() : original; 
    } 

    protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original) 
    { 
     List<MemberBinding> list = null; 

     for (int i = 0, n = original.Count; i < n; i++) 
     { 
      MemberBinding b = this.VisitBinding(original[i]); 

      if (list != null) 
      { 
       list.Add(b); 
      } 
      else if (b != original[i]) 
      { 
       list = new List<MemberBinding>(n); 

       for (int j = 0; j < i; j++) 
       { 
        list.Add(original[j]); 
       } 

       list.Add(b); 
      } 
     } 

     if (list != null) 
     { 
      return list; 
     } 

     return original; 
    } 

    protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) 
    { 
     Expression e = this.Visit(assignment.Expression); 

     if (e != assignment.Expression) 
     { 
      return Expression.Bind(assignment.Member, e); 
     } 

     return assignment; 
    } 

    protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) 
    { 
     IEnumerable<MemberBinding> bindings = this.VisitBindingList(binding.Bindings); 

     if (bindings != binding.Bindings) 
     { 
      return Expression.MemberBind(binding.Member, bindings); 
     } 

     return binding; 
    } 

    protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) 
    { 
     IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(binding.Initializers); 

     if (initializers != binding.Initializers) 
     { 
      return Expression.ListBind(binding.Member, initializers); 
     } 

     return binding; 
    } 

    protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original) 
    { 
     List<ElementInit> list = null; 

     for (int i = 0, n = original.Count; i < n; i++) 
     { 
      ElementInit init = this.VisitElementInitializer(original[i]); 

      if (list != null) 
      { 
       list.Add(init); 
      } 
      else if (init != original[i]) 
      { 
       list = new List<ElementInit>(n); 

       for (int j = 0; j < i; j++) 
       { 
        list.Add(original[j]); 
       } 

       list.Add(init); 
      } 
     } 

     if (list != null) 
     { 
      return list; 
     } 

     return original; 
    } 

    protected virtual ElementInit VisitElementInitializer(ElementInit initializer) 
    { 
     ReadOnlyCollection<Expression> arguments = this.VisitExpressionList(initializer.Arguments); 

     if (arguments != initializer.Arguments) 
     { 
      return Expression.ElementInit(initializer.AddMethod, arguments); 
     } 

     return initializer; 
    } 
} 

Trả lời

0

Trong tiện ích thử thay thế các phương pháp soạn với những điều sau đây.

{ 
    var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); 

    var secondRebound = ParameterRebinder.ReplaceParameters(map, second); 

    return Expression.Lambda<T>(merge(first.Body, secondRebound.Body), first.Parameters); 
} 
Các vấn đề liên quan