实现存储库模式的最佳方式?

Mic*_*ook 36 c# bdd domain-driven-design repository-pattern

我一直在探索BDD/DDD,因此试图找到Repository模式的正确实现.到目前为止,很难就实现这一点的最佳方式达成共识.我试图将其归结为以下变化,但我不确定哪种方法最好.

作为参考,我正在构建一个以NHibernate作为后端的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);
}
Run Code Online (Sandbox Code Playgroud)

我最初的想法是

1)从效率的角度来看是很好的,但随着事情变得更加复杂,我可能会遇到麻烦.

2)看起来非常繁琐,可能最终会出现一个非常拥挤的类,但除此之外,我喜欢的域逻辑和数据层之间存在高度分离.

3)前面看起来很困难,编写查询的工作也比较多,但是只限于Specs层的交叉污染.

4)我最不喜欢的,但可能是最直接的实现,可能大多数数据库对复杂查询有效,尽管它对调用代码负有很多责任.

dth*_*her 22

对于"以上都不是"的方法,也有一个很好的论据.

通用存储库的问题在于您假设系统中的所有对象都支持所有四种CRUD操作:创建,读取,更新,删除.但在复杂系统中,您可能只有少数几个操作的对象.例如,您可能具有只读对象或已创建但从未更新的对象.

您可以将IRepository接口分解为小型接口,用于读取,删除等,但这很快就会变得混乱.

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

有关备用视图,请参阅此Ayende 博客文章.


Fre*_*oux 10

我认为它们都是不错的选择(如果你不想把自己束缚于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);
}
Run Code Online (Sandbox Code Playgroud)

还有一个Repository(of T)基类.


Mic*_*ann 6

我们正在做的一件事是我们所有的存储库都有不同的需求,所以我们创建了一个接口集合:

public interface IReadOnlyRepository<T,V>
{
   V Find(T);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,只读存储库只是从数据库获取.T,V的原因是V表示存储库返回的内容,T表示传入的内容,因此您可以执行以下操作:

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

    public Customer Find(string customerName)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我还可以为Add,Update和Delete创建单独的接口.这样,如果我的存储库不需要该行为,那么它就不会实现该接口.