Brosto
Brosto

Reputation: 4565

NHibernate - dynamic QueryOver parameter

I have an MVC project that I'm trying to setup a nice paging solution for.

I have several tables in SQL Server that have several thousand rows that I would like to be able to page through. If I don't have any type of filter to apply to the paging, it works great. This is the method I'm using to do that:

    public virtual PagedList<T> GetPagedData(int startIndex, int count) {
        var rowCount = session.CreateCriteria(typeof(T)).SetProjection(Projections.RowCount()).FutureValue<Int32>().Value;
        var pageOfItems = session.CreateCriteria(typeof(T)).SetFirstResult(startIndex).SetMaxResults(count).List<T>();
        return new PagedList<T>(pageOfItems, startIndex, count, rowCount);
    }

I also want the ability to pass in a query to narrow the results down even further, and return a new paging table. What I have so far is:

    public virtual PagedList<T> GetPagedData<T>(int startIndex, int count, System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T : class {
        var rowCount = session.QueryOver<T>().Where(predicate).Select(Projections.RowCount()).FutureValue<Int32>().Value;

        var pageOfItems = session.QueryOver<T>().Where(predicate).Skip(startIndex).Take(count).List<T>();
        return new PagedList<T>(pageOfItems, startIndex, count, rowCount);
    }

The call to this would look something like this:

networks = mRepository.GetPagedData<Network>(page ?? 1, pageSize, x => x.Name.Contains(q));

The problem is, it doesn't like the "Contains" expression. If I do an exact match, it works fine (x.Name == q), but I don't get the results I'm after.

The exception I'm seeing using "Contains" is:

Unrecognised method call: System.String:Boolean Contains(System.String)

Does anyone have an idea how to get this to accept an expression like this dynamically? I have a base repository class that I've put this in, because I'll use the same type of behavior for several other tables. I could write a separate method for each table, but I would rather do this dynamically if it's possible.

Thanks for any advice!

Upvotes: 1

Views: 4507

Answers (2)

xanatos
xanatos

Reputation: 111940

With the QueryOver you have to use the extension method IsLike, so x.Name.IsLike(q, MatchMode.Anywhere).

Upvotes: 0

Diego Mijelshon
Diego Mijelshon

Reputation: 52753

QueryOver is not LINQ, and it only accepts a very limited set of expressions.

My suggestion is that you rewrite your method to use LINQ, by replacing QueryOver with Query. The only problem is that it's harder to do the Count using a future query (see this answer for details)

Here's a version without Future:

public virtual PagedList<T> GetPagedData<T>(int startIndex, int count,
               Expression<Func<T, bool>> predicate) where T : class
{
    var query = session.Query<T>().Where(predicate);
    var rowCount = query.Count();
    var page = query.Skip(startIndex).Take(count).List<T>();
    return new PagedList<T>(pageOfItems, startIndex, count, rowCount);
}

Upvotes: 3

Related Questions