Search code examples
sqlnhibernatefluent-nhibernatequeryover

Is there a way to create a property filter sort with Nhibernate QueryOver


I have scenario where I need to conduct the sorting on a property (User.Name) in the NHibernate QueryOver query where the property contains a string that I need to grab the last portion of a name and order ASC. If I was doing it on the returned results, it might be something like:

.....
var query = session.QueryOver<User>().....
.....
query.OrderBy(u => SortByLastName(u.Name));

private string SortByLastName(string name)
    {
        if (string.IsNullOrEmpty(name)) {
            name = " ";
        }

        var nameArray = name.Trim().Split(' ');
        var lastName = nameArray[nameArray.Length - 1];

        return lastName.ToLower();
    }

In SQL it would be a combination of the SUBSTRING, CHARINDEX (and possibly other functions) to grab the last portion of a name (ie. Joe Smith, Jane A. Doe) and sort on the last name.

Question

Is there a way in NHibernate QueryOver to set this up where you didn't have to roll it up in a Stored Proc which is called by the NHibernate or passing in the Raw SQL query through .CreateSQlQuery(sql)?

But instead build this logic directly into the QueryOver?


Solution

  • You can do this by creating Projections that call SQL functions. In your case there are nested functions, so there will be multiple building steps.

    Here is a draft solution. I haven't tested it, but it gives the idea of the approach:

    IProjection nameField = Projections.Property<User>(u => u.Name);
    IProjection charIndex = Projections.SqlFunction("CHARINDEX",
                                                    NHibernateUtil.String,
                                                    nameField,
                                                    Projections.Constant(" ", NHibernateUtil.String)
                                                   );
    IProjection subString = Projections.SqlFunction("SUBSTRING",
                                                    nHibernateUtil.String,
                                                    nameField,
                                                    charIndex,
                                                    Projections.Constant(999, NHibernateUtil.UInt32);
    
    
    
    var query = session.QueryOver<User>().OrderBy(subString).Asc;
    

    Unfortunately, this solution would not work if there are spaces in the first name. (Jane A. Doe). I'm not aware of an SQL function to find the last space in a string.

    See this discussion: Find index of last occurrence of a sub-string using T-SQL