2014-01-30 29 views
4

我见过关于存储库模式的各种博客帖子(以及许多相互矛盾的建议),所以我首先要说的是,很多人认为下面的代码很可能是而不是。然而,这是一个通用的实现,并且它是否遵守Fowler的原始定义,我仍然有兴趣了解更多关于这个实现如何在实践中使用的知识。如何通过存储库模式执行聚合操作?

假设我有一个项目,通过一个接口抽象数据访问,如下面的接口,它提供了基本的CRUD操作。

public interface IGenericRepository<T> 
{ 
    void Add(T entity); 
    void Remove(T entity); 
    void Update(T entity); 
    IEnumerable<T> Fetch(Expression<Func<T,bool>> where); 
} 

进一步假设我有之上构建一个服务层,例如:

public class FooService 
{ 
    private IGenericRepository<Foo> _fooRespository; 

    ... 

    public IEnumerable<Foo> GetBrightlyColoredFoos() 
    { 
     return _fooRepository.Fetch(f => f.Color == "pink" || f.Color == "yellow"); 
    } 
} 

现在假设我现在需要知道多少鲜艳Foo那儿是不实际想要列举它们。理想情况下,我想在我的服务中实现一个CountBrightlyColoredFoos()方法,但是存储库实现让我无法实现这一点,除非将它们全部提取并计数 - 这可能非常低效。

我可以扩展存储库添加Count()方法,但怎么样,我可能需要其他的聚合函数,如Min()Max(),或Sum(),还是......你的想法。

同样,如果我想获得不同的Foo颜色列表(SELECT DISTINCT),该怎么办。同样,简单的存储库也没有办法做这种事情。

保持资源库简单以便于测试/模拟是非常值得赞赏的,但您如何解决这些需求?当然,只有两种方式可以使用 - 一个更复杂的存储库,或者服务层使用的绕过存储库的“后门”(从而破坏其目的)。

+3

能IEnumerable的''是一个IQueryable的''这里,用适当的LINQ提供程序?如果可能,这将是更可取的,因为它提供了解决'IEnumerable '提取方法限制的机会。 –

+0

我想,只要服务层方法返回'IEnumerable',那么库层就可以使用'IQueryable'。我知道这只是一种双向的想法,但我确实喜欢IEnumerable的简单性(特别是测试)... –

+0

总是有'公共静态的IQueryable AsQueryable已(这IEnumerable的源)'进行单元测试目的返回一个存根'的IEnumerable '作为'IQueryable的' –

回答

3

我会说你需要改变你的设计。你想要做的是有一个“主”通用知识库,它有你的基本CRUD,但也有每个实体的较小的知识库。然后,您只需要在某些操作的位置(如总和,数量,最大等等)划出一条线,很可能不是所有的实体都必须进行计数,求和等,并且大多数时候您将无法添加适用于聚合函数的所有实体的通用版本。

基础信息库:

public abstract class BaseRep<T> : IBaseRep<T> where T : class 
{ 
    //basic CRUD 
} 

富库:

public class FooRep : BaseRep<Foo>, IFooRep 
{ 
    //foo specific functions 
} 
+0

接口隔离原理 –

+0

你的意思是说通用接口有CRUD操作,然后像'FooRepository'这样的东西可能会实现这个以及其他一些东西?所以它是“更小”的,因为它实现了更多:-) –

+1

我认为@SOfanatic意味着,是的。你有一个泛型操作的接口,如果你需要提供额外的操作,例如'Count()'等,这些操作构成另一个接口的基础。然后,特定的存储库将实现通用存储库接口以及必要时可选的其他接口 –