I have Fluent NHibernate Linq queries where I check values based on run time arrays. A basic example would be something like:
var array = [1,2,3,4,5,6];
using (var session = SessionProvider.SessionFactory.OpenSession())
{
return session.Query<MyObject>().Where(x => array.Contains(x.CompareVal)).ToList();
}
I would expect the generated SQL statement to look something like this:
SELECT CompareVal, Column1, Column2
FROM MyObject
WHERE CompareVal IN (1,2,3,4,5,6)
However, what I'm finding instead is that the generated SQL statement simply emits the WHERE clause (proven by watching in Profiler) and selects the entire table, and then seems to run the filter in memory once it gets all the data back.
Something to note - I have a Generic Repository class that all of these calls are funneled through. The Query method is as follows:
public IList<T> Query(Func<T, bool> criteria)
{
using (var session = SessionProvider.SessionFactory.OpenSession())
{
return session.Query<T>().Where(criteria).ToList();
}
}
Obviously this (lack of a where clause) is not acceptable in a table with a large amount of data. What can I do to force NHibernate to generate the query correctly with the WHERE clause and still keep a generic pattern for repositories?
Does it make a difference if you change your Query method to the following ?
public IList<T> Query(Expression<Func<T, bool>> criteria)
{
using (var session = SessionProvider.SessionFactory.OpenSession())
{
return session.Query<T>().Where(criteria).ToList();
}
}
This is how I usually proceed with a generic Query :
public List<TOut> GetEntitiesLinq<TIn,TOut>(Expression<Func<IQueryable<TIn>,IQueryable<TOut>>> myFunc)
{
var t = (myFunc.Compile())(_session.Query<TIn>()) ;
return t.ToList();
}
Then how I would use it in your case :
var myObjList = myQueryManager.GetEntitiesLinq<MyObject,MyObject>(x=>x.Where(myObj => array.Contains(myObj.CompareVal)));
Hope this will help
Use Any:
return session.Query<MyObject>().Where(x => array.Any(y => y == x.CompareVal)).ToList();
Your repository pattern (using plain Func) automatically materializes your query to list, if you want something to be deferredly executed, use IQueryable, don't use Func only
Something to note - I have a Generic Repository class that all of these calls are funneled through. The Query method is as follows:
public IList<T> Query(Func<T, bool> criteria)
{
using (var session = SessionProvider.SessionFactory.OpenSession())
{
return session.Query<T>().Where(criteria).ToList();
}
}
Your repository just mimic what is already provided out of the box by NHibernate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With