5

我已经使用 Linq 实现了规范模式,如此处所述https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer

我现在想添加急切加载的能力,但不确定最好的方法。

链接示例中的通用存储库类:

public IEnumerable<T> FindAll(Specification<T> specification)
{
  var query = GetQuery(specification);
  return Transact(() => query.ToList());
}

public T FindOne(Specification<T> specification)
{
  var query = GetQuery(specification);
  return Transact(() => query.SingleOrDefault());
}

private IQueryable<T> GetQuery(
  Specification<T> specification)
{
  return session.Query<T>()
    .Where(specification.IsSatisfiedBy());
}

以及规范实现:

public class MoviesDirectedBy : Specification<Movie>
{

 private readonly string _director;

 public MoviesDirectedBy(string director)
 {
   _director = director;
 }

 public override
    Expression<Func<Movie, bool>> IsSatisfiedBy()
 {
   return m => m.Director == _director;
 }
}

这工作得很好,我现在想添加能够急切加载的能力。我了解 NHibernate 急切加载可以通过在查询上使用Fetch来完成。

我正在寻找的是是否将预先加载的逻辑封装在规范中或将其传递到存储库中,以及实现这一点所需的 Linq/表达式树语法(即如何完成的示例)。

4

2 回答 2

3

一个可能的解决方案是扩展 Specification 类以添加:

public virtual IEnumerable<Expression<Func<T, object>>> FetchRelated
{
    get
    {
        return Enumerable.Empty<Expression<Func<T, object>>>();
    }
}

并将 GetQuery 更改为:

        return specification.FetchRelated.Aggregate(
            session.Query<T>().Where(specification.IsSatisfiedBy()),
            (current, related) => current.Fetch(related));

现在您所要做的就是在需要时覆盖 FetchRelated

public override IEnumerable<Expression<Func<Movie, object>>> FetchRelated
{
    get
    {
        return new Expression<Func<Movie, object>>[]
                     {
                         m => m.RelatedEntity1,
                         m => m.RelatedEntity2
                     };
    }
}

我刚刚编写的这个实现的一个重要限制是您只能获取与根实体直接相关的实体。

一个改进是支持任意级别(使用ThenFetch),这将需要对我们使用泛型的方式进行一些更改(我曾经object允许轻松组合不同的实体类型)

于 2010-12-06T16:25:29.113 回答
1

您不想将 Fetch() 调用放入规范中,因为它不是必需的。规范只是为了限制可以在代码的许多不同部分之间共享的数据,但是这些其他部分在他们想要呈现给用户的数据方面可能有截然不同的需求,这就是为什么在这些点上添加你的获取语​​句。

于 2010-12-16T03:01:38.960 回答