Nhibernate + QueryOver: filter with Where ignoring sensitive
Asked Answered
B

5

10

I am trying to build a simple query in nHibernate with QueryOver but I want it to convert everything lower-case or ignore sensitive:

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

How can I achieve this?

UPDATE:

Someone suggested that the problem could be with the colletion of the DB but I've never had any kind of problem with that and this script works:

Domain.User User = Session
    .CreateCriteria<Domain.User>() 
    .Add(Expression.Eq("Login", "username")) 
    .UniqueResult<Domain.User>(); 
Baht answered 9/3, 2011 at 10:39 Comment(1)
What is your database server and default database collation?Apodaca
S
17

In QueryOver you can use following:

Domain.User User = Session.QueryOver<Domain.User>()
       .WhereRestrictionOn(x=>x.Login).IsInsensitiveLike("username")
       .SingleOrDefault();
Squalor answered 9/3, 2011 at 12:5 Comment(6)
how could you explain the fact that the CreateCriteria works properly?Baht
By default SQL server makes case insensitive strings comparison, but can be configured differently. ICriteria doesn't add anything in SQL it will just generate where Login = 'username'. Can't say it about QueryOver. You should check what SQL it produces. Insensitive like will cause ToLower call in SQLSqualor
I just ran into a problem with solution. In this case, the username had an underscore character in it, and Oracle treats the underscore as a wildcard. So I had both bob.marley and bob_marley in the database and the SingleOrDefault crashed.Natch
Careful - allowing user input to be a LIKE expression is very prone to being a big security hole. NB, the OP did not ask for a Like, but for equality (which would make sense)Rivy
You should probably read question carefully before putting "valuable" commentsSqualor
This logic is not the same as the question requires. Be careful with that "like".Counterinsurgency
H
6

my workaround for this is using a expression.eq combined with a projection, so a case insensitive equals without any magic strings can be done with queryover

query.Where(Expression.Eq(Projections.Property(Of MyType)
                (Function(x) x.Name), "something").IgnoreCase)
Haemostat answered 11/4, 2013 at 8:20 Comment(1)
The exact syntax above didn't work. Here is what worked for me: query.Where(Restrictions.Eq(nameof(MyClass.Property), value).IgnoreCase());Unrelenting
A
2

Better way is to change collation of your database to case insensitive one. If you can change database.

Apodaca answered 9/3, 2011 at 11:33 Comment(4)
Darius, I don't know if it is a problem with the collection cause CreateCriteria works properly:Domain.User User = Session.CreateCriteria<Domain.User>() .Add(Expression.Eq("Login", "username")) .UniqueResult<Domain.User>();Baht
@Baht - If your collation is case insensitive you don't have to specify case sensitivity in your query (all queries will be case insensitive by default).Apodaca
You're right Darius but changing collation in Oracle is not as easy as in Sql Server and I can't do it cause I am not the owner of the DB.Baht
np ;) - as I wrote 'If you can change database...'Apodaca
C
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()));
    }
}

Usages:

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

ChildDTO childAlias = null;
Session.QueryOver<DTO>()
           .JoinAlias(t => t.ChildDTO, () => childAlias)
           .WhereEqualInsensitive(() => myAlias.Property, value)
Counterinsurgency answered 8/2, 2017 at 9:36 Comment(0)
H
0

NH 3.0 has a linq provider so you can use

Session.Query<Domain.User>()
           .Where(x=>x.Login.ToLower() =="username")
           .SingleOrDefault();
Handball answered 9/3, 2011 at 10:42 Comment(5)
I've already tried that. It doesn't work. I get this error: {"Unrecognised method call in epression x.Login.ToLower()"} . could it be cause I am using oracle?Baht
@Baht what version nhibernate you have?Handball
I've checked and the behavior is the same in Sql Server 2008: Unrecognised method call in epression x.Login.ToLower()Baht
@Baht Confirm not working with QueryOver but working with linq to nhibernate. All i can to recomend you its use linq for nhibernate. its all ok with linq in version 3.0Handball
It's strange cause if I create a critiria is case insensitive (and works): Domain.User User = Session.CreateCriteria<Domain.User>() .Add(Expression.Eq("Login", "username")) .UniqueResult<Domain.User>();Baht

© 2022 - 2024 — McMap. All rights reserved.