Gar*_*ill 5 c# entity-framework repository-pattern
我看过有关存储库模式的各种博客文章(以及许多相互矛盾的建议),因此我首先要说的是,在许多人看来,下面的代码可能不遵循存储库模式。然而,这是一个足够常见的实现,无论它是否遵循 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);
}
Run Code Online (Sandbox Code Playgroud)
进一步假设我在其之上构建了一个服务层,例如:
public class FooService
{
private IGenericRepository<Foo> _fooRespository;
...
public IEnumerable<Foo> GetBrightlyColoredFoos()
{
return _fooRepository.Fetch(f => f.Color == "pink" || f.Color == "yellow");
}
}
Run Code Online (Sandbox Code Playgroud)
现在假设我现在需要知道有多少个颜色鲜艳的Foos,但实际上不想枚举它们。理想情况下,我想在我的服务中实现一个CountBrightlyColoredFoos()方法,但是存储库实现让我无法实现这一目标,只能获取所有这些方法并对其进行计数 - 这可能非常低效。
我可以扩展存储库以添加Count()方法,但是我可能需要的其他聚合函数(例如Min()or Max()、or Sum()、or...)怎么样,您明白了。
同样,如果我想获取不同 Foo 颜色的列表 ( SELECT DISTINCT),该怎么办?同样,简单的存储库也无法提供执行此类操作的方法。
保持存储库简单以使其易于测试/模拟是非常值得称赞的,但是如何满足这些要求呢?当然,只有两种方法可以选择 - 更复杂的存储库,或者服务层使用的绕过存储库的“后门”(从而违背了其目的)。
我想说你需要改变你的设计。您想要做的是拥有一个“主”通用存储库,其中包含基本的 CRUD,但也为每个实体提供较小的存储库。然后,您只需在放置某些操作(例如求和、计数、最大值等)的位置画一条线。很可能并非所有实体都必须进行计数、求和等,并且大多数时候您将无法添加适用于聚合函数的所有实体的通用版本。
基础存储库:
public abstract class BaseRep<T> : IBaseRep<T> where T : class
{
//basic CRUD
}
Run Code Online (Sandbox Code Playgroud)
Foo 存储库:
public class FooRep : BaseRep<Foo>, IFooRep
{
//foo specific functions
}
Run Code Online (Sandbox Code Playgroud)