NHibernate + QueryOver:使用Where过滤时忽略大小写敏感性

10

我正在尝试使用QueryOver构建一个简单的查询,但我希望它将所有内容转换为小写或忽略大小写:

Domain.User User = Session.QueryOver<Domain.User>()
       .Where(x=>x.Login=="username")
       .SingleOrDefault();

我该如何实现这个?

更新:

有人建议问题可能出在数据库的收集上,但我从来没有遇到任何这方面的问题,而且这个脚本是可以工作的:

Domain.User User = Session
    .CreateCriteria<Domain.User>() 
    .Add(Expression.Eq("Login", "username")) 
    .UniqueResult<Domain.User>(); 

你的数据库服务器和默认数据库排序规则是什么? - Darius Kucinskas
5个回答

17

在 QueryOver 中,您可以使用以下内容:

Domain.User User = Session.QueryOver<Domain.User>()
       .WhereRestrictionOn(x=>x.Login).IsInsensitiveLike("username")
       .SingleOrDefault();

你如何解释CreateCriteria函数正常工作的事实? - LeftyX
默认情况下,SQL Server 进行大小写不敏感的字符串比较,但可以进行不同的配置。ICriteria 不会在 SQL 中添加任何内容,它只会生成 where Login = 'username'。QueryOver 就不能这样说了,您应该检查它生成的 SQL。Insensitive like 会导致在 SQL 中调用 ToLower。 - Sly
我刚遇到一个有解决方案的问题。在这种情况下,用户名中有一个下划线字符,而 Oracle 将下划线视为通配符。因此,我的数据库中既有 bob.marley 也有 bob_marley,导致 SingleOrDefault 崩溃了。 - Greg
6
小心 - 允许用户输入LIKE表达式非常容易成为一个安全漏洞。需要注意,OP并没有要求Like,而是等式比较(这是有意义的)。 - Ruben Bartelink
在发表“有价值”的评论之前,您应该仔细阅读问题。 - Sly
这个逻辑与问题要求的不同。小心使用“like”。 - Th3B0Y

6

我处理这个问题的方法是使用expression.eq与projection相结合,因此可以使用queryover进行不区分大小写但没有任何神奇字符串的等于比较。

query.Where(Expression.Eq(Projections.Property(Of MyType)
                (Function(x) x.Name), "something").IgnoreCase)

1
上面的确切语法不起作用。这是我生效的内容: query.Where(Restrictions.Eq(nameof(MyClass.Property), value).IgnoreCase()); - katrash

2
更好的方法是将您的数据库排序规则更改为不区分大小写的排序规则。如果您可以更改数据库。

Darius,我不知道是否与集合有关,因为CreateCriteria正常工作:Domain.User User = Session.CreateCriteria<Domain.User>() .Add(Expression.Eq("Login", "username")) .UniqueResult<Domain.User>(); - LeftyX
1
@LeftyX - 如果您的排序规则是不区分大小写的,则无需在查询中指定大小写敏感性(所有查询默认情况下都是不区分大小写的)。 - Darius Kucinskas
你是对的Darius,但在Oracle中改变排序规则并不像Sql Server那样容易,而且我不能这样做,因为我不是该数据库的所有者。 - LeftyX
np ;) - 正如我所写的'如果您可以更改数据库...' - Darius Kucinskas

1
public static class QueryOverExtension
{
    /// <summary>
    /// This method is used in cases where the root type is required
    /// Example: .WhereEqualInsensitive(t => t.Property, stringValue)
    /// </summary>
    public static IQueryOver<T, TU> WhereEqualInsensitive<T, TU>(this IQueryOver<T, TU> queryOver, Expression<Func<T, object>> path, string value)
    {
        return queryOver.Where(Restrictions.Eq(Projections.SqlFunction("upper", NHibernateUtil.String, Projections.Property(path)), value.ToUpper()));
    }

    /// <summary>
    /// This method is used in cases where the root type is NOT required
    /// Example: .WhereEqualInsensitive(() => addressAlias.DefaultEmail, contactEmailAddress)
    /// </summary>
    public static IQueryOver<T, TU> WhereEqualInsensitive<T,TU>(this IQueryOver<T, TU> queryOver, Expression<Func<object>> path, string value)
    {
        return queryOver.Where(Restrictions.Eq(Projections.SqlFunction("upper", NHibernateUtil.String, Projections.Property(path)), value.ToUpper()));
    }
}

用途:

Session.QueryOver<DTO>()
           .WhereEqualInsensitive(t => t.Property, value)

ChildDTO childAlias = null;
Session.QueryOver<DTO>()
           .JoinAlias(t => t.ChildDTO, () => childAlias)
           .WhereEqualInsensitive(() => myAlias.Property, value)

0
NH 3.0有一个Linq提供程序,因此您可以使用它。
Session.Query<Domain.User>()
           .Where(x=>x.Login.ToLower() =="username")
           .SingleOrDefault();

我已经尝试过了,但它不起作用。我收到了这个错误信息:{"Unrecognised method call in epression x.Login.ToLower()"}。难道是因为我正在使用Oracle吗? - LeftyX
@LeftyX,你用的是哪个版本的 nhibernate? - Sanja Melnichuk
我已经检查过了,在Sql Server 2008中的行为是相同的:在表达式x.Login.ToLower()中存在无法识别的方法调用。 - LeftyX
@LeftyX 确认在使用 QueryOver 时无法工作,但在使用 NHibernate 的 Linq 时可以正常工作。我建议您使用 NHibernate 的 Linq。在版本 3.0 中,Linq 工作得很好。 - Sanja Melnichuk
很奇怪,因为如果我创建一个不区分大小写的条件(并且它有效):Domain.User User = Session.CreateCriteria<Domain.User>() .Add(Expression.Eq("Login", "username")) .UniqueResult<Domain.User>(); - LeftyX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接