2

我正在尝试为我的 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>()吗?如果是这样,我怎样才能做到这一点?

4

2 回答 2

5

查询应由 call 执行ToList()

WHERE 子句未包含在您的 sql 语句中的情况是您需要将 an 传递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();

    }

扩展方法在EnumerableWhere(Func<T,bool>>)上定义,以便查询加载所有数据,然后在内存中应用 WHERE 过滤器。

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

于 2013-03-22T08:56:56.367 回答
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() 附加到数据库查询中。

Of course not all linq operations are supported by IQueryable like (join , last ) and this is the only place to call ToList() extension to evaluate expression.

于 2013-03-22T09:21:44.683 回答