代码之家  ›  专栏  ›  技术社区  ›  David Wengier

确定MemberExpressions目标的范围

  •  2
  • David Wengier  · 技术社区  · 16 年前

    我要做的是告诉一个作为业务对象属性的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 并尝试确定它是一个局部变量,还是作为Linq表达式的一部分。

    Type 财产,以及 IsAutoClass ,但那只是猜测,因为它包含了Auto这个词。但没用:)

    3 回复  |  直到 13 年前
        1
  •  1
  •   casperOne    16 年前

    好吧,我不知道您是否可以将它缩减为一次传递,但是您可以获取有关该成员的信息,如果它与您声明为查询一部分的另一个变量(在本例中为“o”)一致,则使用它生成查询。

    否则,假设它是一个常量,然后插入该值。

        2
  •  1
  •   David Wengier    16 年前

    好的,经过一些快速的统计分析(即,手动比较各个属性),DeclaringType、ReflectedType和Namespace是在Lambda参数不在范围内时触发的。

    所以除非有人想出更好的答案,否则我就只能这样了。

        3
  •  1
  •   Marc Gravell    16 年前

    在Where表达式中,您正在查看 Expression<Func<T,bool>> -这意味着最外层的lambda应该有一个 ParameterExpression 带类型 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;
        }    
    }