NHibernate 2和3都会出现这个问题。我有一个A类,它有一个B类成员集。直接执行类很好地执行。但是当我将一个涉及B类的表达式传递给一个方法时,我得到以下错误:
System.ArgumentException:'System.Linq.Expressions.ConstantExpression'类型的对象无法转换为'System.Linq.Expressions.LambdaExpression'类型。
据我所知,我将完全相同的表达式传递给Any()方法。但出于某种原因,他们受到不同的待遇。我做了一些调试,看起来在第一个方法中,表达式被视为具有NodeType'Quote'的表达式,而第二个方法中的相同表达式似乎被视为具有NodeType'Constant'的表达式。第二种方法中表达式的父表达式具有NodeType“MemberAccess”。所以看起来表达式树在不同的测试方法中是不同的。我只是不明白为什么以及如何解决这个问题。
课程涉及:
public class A
{
public virtual int Id { get; set; }
public virtual ISet<B> DataFields { get; set; }
}
public class B
{
public virtual int Id { get; set; }
}
示例测试代码:
[TestMethod]
public void TestMethod1()
{
using (ISession session = sessionFactory.OpenSession())
{
var records = session.Query<A>()
.Where<A>(a => a.DataFields
.Any(b => b.Id == 1));
Console.Write("Number of records is {0}", records.Count());
}
}
[TestMethod]
public void TestMethod2()
{
GetAsWhereB(b => b.Id == 1);
}
private void GetAsWhereB(Func<B, bool> where)
{
using (ISession session = sessionFactory.OpenSession())
{
var records = session.Query<A>()
.Where(a => a.DataFields
.Any(where));
Console.Write("Number of records is {0}", records.Count());
}
}
答案 0 :(得分:5)
这是一个问题:
private void GetAsWhereB(Func<B, bool> where)
这是一个委托 - 你想要一个表达式树,否则NHibernate无法参与其中。试试这个:
private void GetAsWhereB(Expression<Func<B, bool>> where)
顺便说一句,由于您使用了空格,您的查询很难阅读。我建议不要:
var records = session.Query<A>().Where<A>(a => a.DataFields.
Any(b => b.Id == 1));
你明确表示“Any”调用是在DataFields上进行的:
var records = session.Query<A>().Where<A>(a => a.DataFields
.Any(b => b.Id == 1));
我还建议您将参数名称从“where”更改为“whereExpression”或“predicate”。无论如何,某种名词:)
答案 1 :(得分:0)
不确定这是否是正确的解决方案。问题就像一个bug,我的解决方案就像一个解决方法。尽管如此,以下工作对我来说很有用,可以归结为通过使用其body和参数来构造新表达式来创建给定表达式的“副本”。
private void GetAsWhereB(Func<B, bool> where)
{
Expression<Func<T, bool>> w = Expression.Lambda<Func<T, bool>>(where.Body, where.Parameters);
using (ISession session = sessionFactory.OpenSession())
{
var records = session.Query<A>()
.Where(a => a.DataFields
.Any(w));
Console.Write("Number of records is {0}", records.Count());
}
}