我已经使用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 /表达式树语法(即如何完成它的示例)
答案 0 :(得分: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
来允许轻松组合不同的实体类型)
答案 1 :(得分:1)
您不希望将Fetch()调用放入规范中,因为它不需要。规范只是为了限制可以在代码的许多不同部分共享的数据,但是那些其他部分可能对他们想要向用户呈现的数据有着截然不同的需求,这就是为什么在这些点上你会添加你的获取语句。