Lambda 表达式编译(== 并与字符相等)



在表达式中使用==Equals比较char类型变量会在NHibernate中产生不同的SQL查询,并导致错误(优化?(行为。

我像这样构建过滤器表达式:

private Expression<Func<T, bool>> BuildFilter<T>(char firstLetter) where T : IEntity
{
    return PredicateBuilder
        .True<T>()
        .And(ft => ft.FirstLetter.Equals(firstLetter));
}

并像这样使用它:

Session.Query<T>().Where(filter)

如果我将 char 与 char 进行比较.Equals它会产生下一个查询:

2017-03-23 12:02:52,499 [10] DEBUG NHibernate.SQL - 
select tag0_.Id as col_0_0_ 
  from [ft].[Tags] tag0_ 
 where @p0=1 and tag0_.FirstLetter=@p1 
order by tag0_.Title asc;@p0 = True 
[Type: Boolean (0:0:0)], @p1 = 'А' [Type: StringFixedLength (4000:0:0)]

正如你所看到的,NHibernate做了FirstLetter变量sql参数(@p1(,这是正确的。

问题

以前,我像这样使用==运算符进行比较:

private Expression<Func<T, bool>> BuildFilter<T>(char firstLetter) where T : IEntity
{
    return PredicateBuilder
        .True<T>()
        .And(ft => ft.FirstLetter == firstLetter);
}

这产生了我的下一个查询:

2017-03-23 12:17:22,718 [23] DEBUG NHibernate.SQL - 
select tag0_.Id as col_0_0_ 
  from [ft].[Tags] tag0_ 
 where @p0=1 
   and tag0_.FirstLetter='А' 
order by tag0_.Title asc;@p0 = True 
[Type: Boolean (0:0:0)]

此查询看起来也正确。

但是,就一瞬间...每次调用具有==比较的方法都会产生具有tag0_.FirstLetter='А'谓词的相同查询,它不关心过滤器表达式中使用的实际字符值!

这看起来像NHibernate缓存或类似的东西?

这是一个已知的错误。您也许可以在 char 属性上调用 .ToString() 并将文本值作为字符串提供以躲避错误,但我不确定。

它的根源在于某些 .Net 编译规则,导致char在 lambda 表达式中转换为 int

目前在主分支(即将推出的 v5(中修复,我不知道它是否会向后移植到 v4。

最新更新