Fluent NHibernate does not create IN part of WHERE clause

不想你离开。 提交于 2019-12-09 03:13:54

问题


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?


回答1:


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




回答2:


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




回答3:


Can you use QueryOver and WhereRestrictionOn instead?

session.QueryOver<MyObject>().WhereRestrictionOn(o => o.CompareVal).IsIn(array).List();


来源:https://stackoverflow.com/questions/14647670/fluent-nhibernate-does-not-create-in-part-of-where-clause

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!