【问题标题】:NHibernate Exception: Unable to cast object of type 'NHibernate.Hql.Ast.HqlParameter' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'NHibernate 异常:无法将“NHibernate.Hql.Ast.HqlParameter”类型的对象转换为“NHibernate.Hql.Ast.HqlBooleanExpression”类型
【发布时间】:2017-01-19 10:46:56
【问题描述】:

我正在尝试查询我的地址位置以找出特定半径内的地址。下面是我的 where 子句,resultsIEnumerable<Properties>

 Func<Address, bool> predicate = l =>
 {
    if (l.Location == null && l.Longitude.HasValue && l.Latitude.HasValue)
    {
       var point = new Point(l.Longitude.Value, l.Latitude.Value);
       return point.Distance(p) <= 300;
    }
    return false;
  };

  results = results.Where(x => predicate(x.Address));

但是,我从 NHibernate 得到一个例外

“无法将“NHibernate.Hql.Ast.HqlParameter”类型的对象转换为“NHibernate.Hql.Ast.HqlBooleanExpression”类型。

我该如何解决这个问题?

非常感谢任何帮助。

【问题讨论】:

  • 我猜 NHibernate 不能通过 sql 在你的数据库中执行你的谓词。尝试使用 NHibernate 可以翻译成 sql 的一些简单类型。
  • 某种意义上的简单类型?你的意思是在这里输入Point
  • 你的数据库理解的东西。 LongitudeLatitude 的类型是什么?是否可以自己进行point.Distance(p) 计算?我不知道Distance() 方法是如何工作的,但也许您可以执行l.Longitude =&gt; 300 &amp;&amp; l.Longitude &lt;= 300 之类的操作。
  • latitude & longitude 只是一个双倍。我对point.Distance(p) 没有任何问题,因为我还有一个非常适合point.Distance(p) 的查询。
  • point.Distance(p) 无法在数据库中执行。您确定不在内存中已获取的集合中执行此操作吗?请查看 NHibernate 为您的工作方法生成的 sql,您会看到 NHibernate 没有在您的数据库中执行 point.Distance(p)。顺便提一句。 results 是什么?这是query 还是List?如果它应该是一个列表,请在.Where() 之前调用.ToList()

标签: c# nhibernate fluent-nhibernate


【解决方案1】:

您需要使用 LINQ 表达式,而不是 lambda! 试试这个:

Expression<Func<Address, bool>> predicate = ...

【讨论】:

  • 不够... 它的 lambda 是一个多行 lambda,使用了一段代码。我不知道有任何 linq 提供商可以处理这个问题。
【解决方案2】:

您的过滤表达式无法转换为 SQL。它是一个多行表达式。 与任何其他 orm LINQ 提供程序一样,需要一个可以转换为 SQL 的简单线性 lambda。

此外,您的过滤表达式使用一个执行某些计算的类(在您的情况下为Distance())。除非您extend it,否则 LINQ 提供程序将不知道如何将其转换为 SQL。如果可以以 SQL 可翻译的方式编写,则更好地在 lambda 中重写您的计算。

如果你在很多地方都需要你的谓词,你可以在使用它之前编写一个函数来获取它在一个本地变量中。

private Expression<Func<Address, bool>> GetFilterByMaxDistance(double maxDistance)
{
    // replace ??? with your computation, without block of code (no `{}`) nor call to 
    // functions not known for being handled by the LINQ provider
    return a => ??? <= maxDistance;
}

...

    var predicate = GetFilterByMaxDistance(300);
    results = results.Where(predicate);

否则,如果您的 results 局部变量已经“充分过滤”以获得合理的性能,请在应用过滤器之前调用 .AsEnumerable(),这一次仅作为 Func&lt;Address, bool&gt;,而不是作为一个Expression&lt;Func&lt;Address, bool&gt;&gt;

在应用 .Where(predicate) 之前调用 .AsENumerable() 将导致您的谓词由 .Net 运行时在内存中执行,而无需将其转换为 SQL。
但这当然会导致过滤发生在您的应用程序中,而不是在数据库中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    相关资源
    最近更新 更多