2009-01-19 72 views
2

有没有人在这里有编写自定义Linq提供者的经验?确定MemberExpressions目标的范围

我想要做的是告诉一个业务对象属性的MemberExpression是否应该包含在SQL中,或者作为一个常量来处理,因为它来自一个本地变量,它恰好是一个业务目的。

因此,举例来说,如果你有这样的:

Customer c = LoadCustomerFromDatabase(); 

var orders = from o in db.Orders() where o.CustomerID == c.CustomerID select o; 

此刻,我的查询翻译器将尝试执行SELECT * FROM orders o where o.CustomerID = c.CustomerID,这当然是行不通的。

我想要做的就是检查c.CustomerID上的MemberExpression,并试着弄清楚它是一个局部变量,还是仅仅用作Linq表达式的一部分。

我已经设法做它作为查询的第二遍,寻找SQL Server将无法绑定,并注入他们的价值观,但如果可能我想这一切都发生与此同时。我尝试着看着Type属性和IsAutoClass,但这只是一个猜测,因为它包含了单词Auto。它没有工作:)

回答

1

嗯,我不知道你是否可以减少到一个通过,但你可以获得有关该成员的信息,如果它与另一个变量一致,你声明为查询的一部分(在本例中为“o”),您可以使用它来生成查询。

否则,你会以为这是一个常数,再插上该值。

不幸的是,因为你可以从语句有(除let语句)在查询多个地方,它不看起来你只需一次就可以做到这一点,因为你需要事先了解所有的查询变量。

1

好了,一些快速统计分析后(即,比较手动个体性质),DeclaringType,ReflectedType和命名空间是当拉姆达参数不在范围内”的火灾。

所以,除非有人想出了一个更好的答案,这可能是我必须去

1

在哪里表达,你正在寻找一个Expression<Func<T,bool>> - 。这意味着最拉姆达应该有一个​​与T

如果比较涉及到该行,它会有(作为祖先)这​​;如果它是局部变量,它将具有(作为祖先)ConstantExpression - 但是,此常量表达式的类型将由编译器生成,以处理表达式中使用的所有捕获的变量。

像这样:

using System; 
using System.Linq.Expressions; 
class Foo 
{ 
    public string Name { get; set; } 
    static void Main() 
    { 
     var exp = (LambdaExpression) GetExpression(); 
     WalkTree(0, exp.Body, exp.Parameters[0]); 

    } 
    static void WriteLine(int offset, string message) 
    { 
     Console.WriteLine(new string('>',offset) + message); 
    } 
    static void WalkTree(int offset, Expression current, 
     ParameterExpression param) 
    { 
     WriteLine(offset, "Node: " + current.NodeType.ToString()); 
     switch (current.NodeType) 
     { 
      case ExpressionType.Constant: 
       WriteLine(offset, "Constant (non-db)" 
        + current.Type.FullName); 
       break; 
      case ExpressionType.Parameter: 
       if (!ReferenceEquals(param, current)) 
       { 
        throw new InvalidOperationException(
         "Unexpected parameter: " + param.Name); 
       } 
       WriteLine(offset, "db row: " + param.Name); 
       break; 
      case ExpressionType.Equal: 
       BinaryExpression be = (BinaryExpression)current; 
       WriteLine(offset, "Left:"); 
       WalkTree(offset + 1, be.Left, param); 
       WriteLine(offset, "Right:"); 
       WalkTree(offset + 1, be.Right, param); 
       break; 
      case ExpressionType.MemberAccess: 
       MemberExpression me = (MemberExpression)current; 
       WriteLine(offset, "Member: " + me.Member.Name); 
       WalkTree(offset + 1, me.Expression, param); 
       break; 
      default: 
       throw new NotSupportedException(
        current.NodeType.ToString()); 
     } 
    } 

    static Expression<Func<Foo, bool>> GetExpression() 
    { 
     Foo foo = new Foo { Name = "abc" }; 

     return row => row.Name == foo.Name; 
    }  
}