我正在尝试为我的NHibernate数据访问编写通用存储库。 Get<T>()
方法应该能够获取一个可选谓词,该谓词应该包含在查询中 - 也就是说,NHibernate应该在SQL中生成WHERE子句。
public virtual IList<T> Get(Func<T, bool> predicate = null)
{
// Open NHibernate Session
using (var session = NHibernateHelper.OpenSession())
return (predicate != null
? session.Query<T>().Where(predicate)
: session.Query<T>()).ToList();
}
当我传入一个谓词,并观察NH生成的SQL语句时,我看不到where子句。
NHibernate何时执行查询?在致电.Query<T>()
时才对吗?如果是这样,我怎么能实现这个目标呢?
答案 0 :(得分:5)
查询应该通过调用ToList()
执行。
您的sql语句中未包含WHERE子句的情况是您需要将Expression<Func<T,bool>>
传递给您的方法。
public virtual IList<T> Get(Expression<Func<T, bool>> predicate = null)
{
// Open NHibernate Session
using (var session = NHibernateHelper.OpenSession())
return (predicate != null
? session.Query<T>().Where(predicate)
: session.Query<T>()).ToList();
}
扩展方法Where(Func<T,bool>>)
在Enumerable上定义,以便查询加载所有数据,然后在内存中应用WHERE过滤器。
扩展方法Where(Expression<Func<T,bool>>)
在Queryable上定义,以便查询提供程序(NHibernate)可以构建一个sql语句,包括在数据源上执行的WHERE条件。
答案 1 :(得分:1)
由于@Jehof给出了正确的解释,我只想添加单独的注释 - 您不应该从存储库方法返回IList<T>
,因为任何其他linq操作将在内存中而不是在数据库中执行。假设以下呼叫
var data = repository.Get<Company>(c=>c.Name.StartsWith("MyCompany"));
... some other operations / method calls etc.
var companySubset = data.Where(...);
所以现在如果你有IList<T> Get<T>()
会降低性能,但是使用IQueryable<T> Get<T>
,你仍然会在数据库查询中附加第二个Where()。
当然并非IQueryable
支持所有linq操作(join,last),这是唯一可以调用ToList()
扩展来评估表达式的地方。