实施Repository模式的最佳方法是什么?

我一直在探索BDD / DDD,并试图提出一个适当的Repository模式的实现。 到目前为止,很难就实现这一目标的最佳方式达成共识。 我试图把它归结为以下变化,但我不确定哪个是最好的方法。

作为参考,我正在用NHibernate构build一个ASP.MVC应用程序作为后端。

public interface IRepository<T> { // 1) Thin facade over LINQ T GetById(int id); void Add(T entity); void Update(T entity); void Remove(T entity); IQueryable<T> Find(); // or possibly even T Get(Expression<Func<T, bool>> query); List<T> Find(Expression<Func<T, bool>> query); } public interface IRepository<T> { // 2) Custom methods for each query T GetById(int id); void Add(T entity); void Update(T entity); void Remove(T entity); IList<T> FindAll(); IList<T> FindBySku(string sku); IList<T> FindByName(string name); IList<T> FindByPrice(decimal price); // ... and so on } public interface IRepository<T> { // 3) Wrap NHibernate Criteria in Spec pattern void Add(T entity); void Update(T entity); void Remove(T entity); IList<T> FindAll(); IList<T> FindBySpec(ISpecification<T> specification); T GetById(int id); } public interface IRepository<T> { // 4) Expose NHibernate Criteria directly T GetById(int id); void Add(T entity); void Update(T entity); void Remove(T entity); IList<T> FindAll(); IList<T> Find(ICriteria criteria); // .. or possibly IList<T> Find(HQL stuff); } 

我最初的想法是

1)从效率的angular度来看是很棒的,但随着事情变得更加复杂,我可能会陷入困境。

2)看起来非常单调乏味,最终会出现一个非常拥挤的类,但在我的域逻辑和我喜欢的数据层之间提供了高度的分离。

3)在前面看起来很困难,而且还有更多的工作要写查询,但限制了交叉污染仅仅是规范层。

4)我最不喜欢的,但可能是最直接的实现,也可能是最复杂的查询数据库效率,虽然它在调用代码上承担了很大的责任。

    我认为他们都是很好的select(如果你不想把自己绑定到nhibernate,也许只有4个),你似乎有很好的分析和利弊分析,根据你目前的努力做出自己的决定。 不要狠狠地打这个

    我目前正在研究2和3之间的混合物我想:

     public interface IRepository<T> { ... IList<T> FindAll(); IList<T> FindBySpec(ISpecification<T> specification); T GetById(int id); } public interface ISpecificRepository : IRepository<Specific> { ... IList<Specific> FindBySku(string sku); IList<Specific> FindByName(string name); IList<Specific> FindByPrice(decimal price); } 

    还有一个Repository(T)基类。

    “以上都不是”的方法也有一个很好的论点。

    通用存储库的问题在于,你假定系统中的所有对象都将支持所有四个CRUD操作:创build,读取,更新,删除。 但是在复杂的系统中,您可能只有一些对象只支持一些操作。 例如,您可能有只读的对象,或创build但从未更新的对象。

    你可以把IRepository接口分成小的接口,读取,删除等等,但是很快就会变得麻烦。

    Gregory Young提出了一个很好的论点(从DDD /软件分层的angular度),每个存储库应该只支持特定于域对象或你正在使用的聚合的操作。 这是他关于通用存储库的文章。

    而另一种观点,请参阅Ayende 博客文章 。

    我们所做的一件事就是我们所有的仓库都有不同的需求,所以我们要创build一个接口集合:

     public interface IReadOnlyRepository<T,V> { V Find(T); } 

    在这个例子中,只读存储库只是从数据库中获取。 T,V的原因是V代表仓库返回的内容,T代表传入的内容,所以你可以这样做:

     public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer> { public Customer Find(int customerId) { } public Customer Find(string customerName) { } } 

    我也可以为添加,更新和删除创build单独的界面。 这样,如果我的存储库不需要的行为,那么它只是不实现接口。

    当使用NH和Linq时,你的仓库可以是:

     session.Linq<Entity>() 

    规格是处理的事情:

     IQueryable<Entity> 

    如果你愿意的话,你可以把它全部拿走,但这是抽象抽象的很多世俗的工作。

    简单很好。 嗯,新罕布什尔州数据库,但它提供了更多的模式。 除了DAL之外的其他因素还远不止于罪孽。

    我是1的bif风扇,因为我可以创buildfilter和分页扩展方法,而不是将其应用于Find方法的IQueryable <>返回值。 我将扩展方法保留在数据层中,然后在业务层中即时构build。 (不完全纯粹,诚然。)

    当然,当系统稳定时,我可以select使用相同的扩展方法来创build特定的Find方法,并使用Func <>进行优化。

    枯萎仓库

    LosTechies的Jimmy Bogard的相关文章

    http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx

    此外,另一篇快速文章,其中一些评论build议版本#2是一个DOA模式,而不是一个存储库。

    http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html

    我相信这取决于你的需求。 将存储库与您考虑使用的其他devise模式结合起来考虑是非常重要的。 最后,这取决于你对仓库的期望是什么(使用它的主要原因是什么)。

    你是否需要创build严格的层(例如将来需要用entity frameworkreplaceNHibernate)? 你想特别写入testing库方法?

    没有最好的方式来创build存储库。 只有几种方法,这绝对取决于你,什么是最适合你的需求。