我正在构建一个表达式树(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))), )]
我做错了什么?这两个选项有什么区别?
答案 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。