我基于您在 UI/控制器/服务中直接使用实体框架的假设来回答您的问题。
已经证明,直接在您的 UI/控制器/服务中使用任何 ORM,包括 EF,将来都会导致很多问题。最重要的是,即使不是不可能,也很难对您的应用程序进行单元测试。
第二种方法,即“模型实现存储库”在我看来也是错误的,因为模型和存储库具有不同的职责,并且基于 SOLID 原则的“单一职责”部分,您不应该将这两个概念合并在一起。即使您想在模型中使用 Active Objects 模式(我不建议这样做),您也必须将模型与您使用的 ORM 分离。
最好和最推荐的解决方案是拥有一个像 IRepository 或 IRepository 这样的接口,其中包含模式所建议的非常基本的成员。就像是:
Interface IRepository<T> where T:class
{
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
// if you don't want to return IQueryable
T FindById(object id);
IEnumerable FindXXXXX(params)
// if you prefer to return an IQueryable
IQueryable<T> Find(Expression<Func<T, bool>> predeicate);
}
请注意,有些人认为存储库不应返回 IQueryable。此外,您可以考虑使用 ISpecification 代替表达式和 lambda。
您需要为大多数实体实现 IRepositoy 接口。使用这种方法,您还可以在编写单元测试时模拟您的存储库。在生产中,您需要使用 Unity、Ninject、Linfu、Catsle 等 Ioc 提供程序。您还可以从 Microsoft 的通用服务定位器实现中受益,以避免耦合到特定的 IoC 框架。
在过去,我曾经有一个为特定业务领域或服务实现的数据访问接口。这种方法的一个问题是,如果您跟踪您的源代码,您最终会在不同的数据访问服务中得到重复的代码,而且您最终会这样做。