2013-03-22 40 views
2

我想为我的NHibernate数据访问编写一个通用的存储库。 Get<T>()方法应该能够接受一个可选谓词,该谓词应该包含在查询中 - 也就是说,NHibernate应该在SQL中生成WHERE子句。NHibernate何时执行我的查询?

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>()?如果是这样,我该如何做到这一点?

回答

6

该查询应该由电话ToList()执行。

为什么WHERE子句不包含在您的sql语句中的原因是您需要将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滤波器。

Queryable上定义了扩展方法Where(Expression<Func<T,bool>>),这样查询提供程序(NHibernate)就可以构建一个sql语句,包括您在数据源上执行的WHERE条件。

+0

谢谢,绝对完美! – Jeff 2013-03-22 09:42:30

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>你仍然会有第二凡()追加到数据库查询。

当然不是所有的linq操作都支持IQueryable like(join,last),这是唯一可以调用ToList()扩展来评估表达式的地方。

+0

这是重点,但感谢您的注意:) - 我不希望我的业务逻辑触发数据库调用时,我没有明确要求它。 – Jeff 2013-03-22 09:41:09