构造表达式树会导致InvalidPathException

时间:2011-01-17 15:13:44

标签: c# .net expression-trees

我正在构建一个表达式树(Expression<Func<PlainAddress, bool>> predicate)以将其传递给HNibernate的IQueryable.Where函数来执行查询。当我通过时:

 predicate = y => y.Address.City == geoObject.Name;
一切正常。当我通过时:

var x = Expression.Parameter(typeof(PlainAddress));

Expression<Func<PlainAddress, string>> expression = y => y.Address.City;

predicate = Expression.Lambda<Func<PlainAddress, bool>>(
    Expression.Equal(
        Expression.Invoke(expression, x), 
        Expression.Constant(geoObject.Name)), 
        x);

我收到以下异常

Invalid path: 'y.Address.City' 
[.Where(NHibernate.Linq.NhQueryable`1[BPPDicsManager.Domain.Entities.PlainAddress], 
Quote((60ee8287-3f42-426a-8c15-41f62f58623c, ) => (String.op_Equality((y, ) => 
(y.Address.City)60ee8287-3f42-426a-8c15-41f62f58623c, p1))), )]

我做错了什么?这两个选项有什么区别?

1 个答案:

答案 0 :(得分:5)

我不熟悉NHibernate,但我可以尝试解释这两个表达式之间的差异。

1.主要区别在于样本#2中使用Expression.Invoke,它创建了一个InvocatonExpression,表示将委托或lambda表达式应用于参数表达式列表的表达式“。这引入了一种间接 - 松散地说,

样品#1是:

y => y.Address.City == geoObject.Name;

而样品#2是 之类的东西:

x => new Func<PlainAddress, string>(y => y.Address.City).Invoke(x) 
     == geoObject.Name

您可以使用Expression.Property创建合适的MemberExpression来使第二个样本更靠近第一个样本:

var predicate = Expression.Lambda<Func<PlainAddress, bool>>(
        Expression.Equal(
            Expression.Property(Expression.Property(x, "Address"), "City"),
            Expression.Constant(geoObject.Name)),
            x);

现在更接近:

x => x.Address.City == AsStringLiteral(geoObject.Name)

(我猜这将足以使谓词与NHibernate一起使用。)


2.当然,另一个不同之处是在样本#2中使用Expression.Constant,它将急切评估geoObject.Name的值并将其转换为<表达式树中的em> literal 。如果您想要“模拟”geoObject变量(或者this?)的悬挂,您将需要更多的工作,如示例#1。