1

我在下面有这个方法可以查询数据库以获取例如用户、订单或任何实体。我想知道下面的查询是最优的还是我必须调整它。

只有在将所有记录存储在内存中之后,查询才会在哪里执行?

有没有办法我可以指定Expression过滤而不是Func<>

获取 Count 的最佳方法是什么,指定一个条件/在哪里没有太多内存消耗?

C# 示例代码

public IList<TEntity> Find(Func<TEntity, bool> predicate)
{
    //Criteria for creating
    ICriteria filterCriterea = _unitOfWork.CurrentSession.CreateCriteria(typeof(TEntity));

    //filtered result
    return filterCriterea.Future<TEntity>().Where(predicate).ToList();
}
4

1 回答 1

2

您需要修复以下几件事:

1. 要求一个Expression,而不是一个Func

您的Find方法指定它需要一个Func. 如果你想要一个Expression,你必须这样说:

public IList<TEntity> Find(Expression<Func<TEntity, bool>> predicate)

2. 使用 LINQ 或QueryOver代替ICriteria

假设您没有使用没有 LINQ 或 QueryOver 的旧版 NHibernate (奇怪的是,还有很多人仍在使用 NHibernate 1.2.1 - 我不知道为什么) ......

ICriteria不明白Expressions。替换CreateCriteria(typeof(TEntity))Query<TEntity>()QueryOver<TEntity>()取决于您喜欢的查询语法。

3.Where应该先去Future

您需要WhereFuture. Future用于将多个查询批处理在一起,以便在您的代码尝试评估“未来”查询之一的结果时,它们都会在一次往返数据库中执行。在您上面的代码调用Future时,查询仅包含CreateCriteria(typeof(TEntity)),它只是告诉它要查询哪个表,如下所示:

select * from TEntity

如果你想要一个 where 子句,你必须切换这些方法调用:

filterCriterea.Where(predicate).Future<TEntity>()

这应该给你一个 SQL 查询,如:

select * from TEntity where ...

IQueryable了解和之间的区别非常重要IEnumerable 你应该注意到Query返回一个IQueryable,而Future返回一个IEnumerable。操作IQueryableusingExpression会导致执行的 SQL 发生变化。IEnumerable使用 a操作Func会改变您查看内存数据的方式。

4.ToList立即Future否定利益后Future

ToList遍历传递给它的集合并将每个元素放入列表中。遍历集合的行为将导致 Future 查询立即执行,而不给您任何机会将它与其他查询一起批处理。如果你必须有一个列表,你应该省略Future. 但是,我认为,将您的方法更改为返回 an 会是一个更好的主意IEnumerable,这将使您能够将此查询与其他查询一起批处理。像这样...

public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
    var query = _unitOfWork.CurrentSession.Query<TEntity>();
    return query.Where(predicate).Future<TEntity>();
}

为了利用查询批处理,您可能必须重新排列调用此Find方法的代码。例如,而不是...

foreach (var openThing in thingRepository.Find(x => x.Status == Status.Open))
    CloseIt(openThing);

foreach (var negativeWhatsit in whatsitRepository.Find(x => x.Amount < 0))
    BePositive(negativeWhatsit);

... 你应该做这个:

var openThings = thingRepository.Find(x => x.Status == Status.Open);
var negativeWhatsits = whatsitRepository.Find(x => x.Amount < 0);

// both queries will be executed here in one round-trip to database
foreach (var openThing in openThings)
    CloseIt(openThing);

foreach (var negativeWhatsit in negativeWhatsits)
    BePositive(negativeWhatsit);
于 2013-10-04T14:47:39.830 回答