6

我有 Fluent NHibernate Linq 查询,我在其中检查基于运行时数组的值。一个基本的例子是这样的:

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();
}

我希望生成的 SQL 语句看起来像这样:

SELECT CompareVal, Column1, Column2
FROM MyObject
WHERE CompareVal IN (1,2,3,4,5,6)

但是,我发现生成的 SQL 语句只是发出 WHERE 子句(通过在 Profiler 中观察证明)并选择整个表,然后似乎在获取所有数据后在内存中运行过滤器。

需要注意的一点 - 我有一个 Generic Repository 类,所有这些调用都通过它汇集。查询方法如下:

public IList<T> Query(Func<T, bool> criteria)
{
  using (var session = SessionProvider.SessionFactory.OpenSession())
  {
    return session.Query<T>().Where(criteria).ToList();
  }
}

显然,这(缺少 where 子句)在具有大量数据的表中是不可接受的。我可以做些什么来强制 NHibernate 使用 WHERE 子句正确生成查询并仍然为存储库保留通用模式?

4

3 回答 3

3

如果您将 Query 方法更改为以下内容,是否会有所不同?

public IList<T> Query(Expression<Func<T, bool>> criteria)
{
  using (var session = SessionProvider.SessionFactory.OpenSession())
  {
    return session.Query<T>().Where(criteria).ToList();
  }
}

这就是我通常使用通用查询的方式:

    public List<TOut> GetEntitiesLinq<TIn,TOut>(Expression<Func<IQueryable<TIn>,IQueryable<TOut>>> myFunc)
    {
        var t = (myFunc.Compile())(_session.Query<TIn>()) ;
        return t.ToList();
    }

那么我将如何在您的情况下使用它:

var myObjList = myQueryManager.GetEntitiesLinq<MyObject,MyObject>(x=>x.Where(myObj => array.Contains(myObj.CompareVal)));

希望这会有所帮助

于 2013-02-01T14:54:22.707 回答
2

使用任何:

 return session.Query<MyObject>().Where(x => array.Any(y => y == x.CompareVal)).ToList();

您的存储库模式(使用普通 Func)会自动将您的查询具体化以列出,如果您希望延迟执行某些内容,请使用 IQueryable,不要仅使用 Func

需要注意的一点 - 我有一个 Generic Repository 类,所有这些调用都通过它汇集。查询方法如下:

public IList<T> Query(Func<T, bool> criteria)
{
  using (var session = SessionProvider.SessionFactory.OpenSession())
  {
    return session.Query<T>().Where(criteria).ToList();
  }
}

您的存储库只是模仿 NHibernate 开箱即用的内容

于 2013-02-01T14:32:28.487 回答
0

您可以改用 QueryOver 和 WhereRestrictionOn 吗?

session.QueryOver<MyObject>().WhereRestrictionOn(o => o.CompareVal).IsIn(array).List();
于 2013-02-01T14:30:07.427 回答