Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fuzzy Search on a Concatenated Full Name using NHibernate

I am trying to convert the following SQL into NHibernate:

SELECT * FROM dbo.Customer
WHERE FirstName + ' ' + LastName LIKE '%' + 'bob smith' + '%'

I was trying to do something like this but it is not working:

name = "%" + name + "%";

var customers = _session.QueryOver<Customer>()
            .Where(NHibernate.Criterion.Restrictions.On<Customer>(c => c.FirstName + ' ' + c.LastName).IsLike(name))
            .List();

What I'm basically trying to do is be able to search for a customer's name in a text box with the example value of "bob smith" and for it to search the database using the LIKE expression in the SQL above.

If I'm going about searching the FirstName and LastName columns wrongly, please help me out with an alternative but the above SQL query gets me what I need.

Update with 2 solutions:

So I've now found two solutions to this problem. One is to use the Criteria API. The following post has an answer that works great: https://stackoverflow.com/a/2937100/670028

The other solution I found thanks to one of my helpful coworkers who suggested using a LINQ projection and anonymous types. Here's a solution using LINQ:

var customers = session.Query<Customer>()
    .Select( x => new { FullName = x.FirstName + " " + x.LastName, Customer = x } )
    .Where( x => x.FullName.Contains( "Bob Smith" ) )
    .Select( x => x.Customer )
    .ToList();
like image 679
Randy Burden Avatar asked Jul 15 '11 15:07

Randy Burden


2 Answers

NHibernate is not able to translate the expression into a sql statement because is does not know what to do with c => c.FirstName + ' ' + c.LastName. A solution can be rewriting this to something like this:

Session.CreateCriteria<Customer>()
    .Add(Restrictions.Like(
    Projections.SqlFunction("concat",
                            NHibernateUtil.String,
                            Projections.Property("FirstName"),
                            Projections.Constant(" "),
                            Projections.Property("LastName")),
    "Bob Whiley",
    MatchMode.Anywhere))
like image 51
Peter Avatar answered Oct 22 '22 01:10

Peter


If you would like to keep your code as strongly-typed as possible, here is how I achieved it. I needed to use it in a Disjunction. Hope this helps someone!

var disjunction = new Disjunction();
var fullNameProjection = Projections.SqlFunction(
    "concat",
    NHibernateUtil.String,
    Projections.Property<UserProfile>(x => x.FirstName),
    Projections.Constant(" "),
    Projections.Property<UserProfile>(x => x.LastName)
    );
var fullNameRestriction = Restrictions.Like(fullNameProjection, searchText, MatchMode.Anywhere);
disjunction.Add(fullNameRestriction);
like image 24
Reaction21 Avatar answered Oct 21 '22 23:10

Reaction21