我已经看过关于存储库模式的各种博客文章(以及很多相互矛盾的建议),所以我首先要说下面的代码可能是而不是遵循许多人的存储库模式意见。然而,这是一个通用的实现,并且它是否遵循福勒的原始定义,我仍然有兴趣了解更多关于如何在实践中使用该实现。
假设我有一个项目,通过下面的接口抽象数据访问,该接口提供基本的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
)的列表,该怎么办?同样,简单的存储库也无法做到这一点。
保持存储库简单以便于测试/模拟是非常值得称赞的,但是您如何解决这些要求呢?当然,只有两种方法可以实现 - 一个更复杂的存储库,或者服务层使用的“后门”绕过存储库(从而无法实现其目的)。
答案 0 :(得分:3)
我会说你需要改变你的设计。你想要做的是有一个“主”通用存储库,它有你的基本CRUD,但每个实体也有一个较小的存储库。然后,您只需要在某处操作(如总和,计数,最大等)放置一条线。很可能并非所有实体都必须计算,求和等等。大多数时候你将无法添加适用于聚合函数的所有实体的通用版本。
Base Repository:
public abstract class BaseRep<T> : IBaseRep<T> where T : class
{
//basic CRUD
}
Foo Repository:
public class FooRep : BaseRep<Foo>, IFooRep
{
//foo specific functions
}