在使用ASP.net MVC和Entity Framework时,我一直在努力实现存储库和服务模式。
我理解存储库模式的目的以及它如何帮助测试并使数据层可以互换。但是,实体框架已经是工作模式的存储库/单元。我见过的存储库模式的每个实现都剥离了EF的有用功能,或者实现了一个使纯粹主义者蠕动的IQueryable<T>
属性。
如果我正在为我的服务层编写接口,那么实现这些服务的具体版本是有原因的,我不应该直接在服务中使用Entity Framework作为我的数据层(而不是将其包装在存储库中)工作单元模式和注入依赖)?例如:我不能创建一个IService
接口,然后创建一个具体的EfService
(实体框架)或NhService
(NHibernate版本)实现?
然后,我可以使用我的IoC容器注入所需的服务和数据上下文。
以下是根据谢尔盖的评论我提出的一个例子:https://github.com/sweeperq/Monona
该模式是如何实现的?
答案 0 :(得分:3)
我总是使用存储库接口。
第一个原因是可测试性 - DbContext
和DbSet<T>
难以模拟。因此,即使可能,服务的单元测试也变得非常困难。
第二个原因是EF公开IQueryable<T>
。它使数据访问逻辑遍布整个应用程序,这违反了SRP并使修复问题更难。
第三个原因可能不是很重要 - 切换接口实现的能力 - 不仅可以使用真实对象和模拟,还可以使用不同的数据访问框架。你总是认为 - “不,我肯定会坚持EF”。但在现实世界中,由于性能问题和易于开发,我有切换到Dapper的经验。一旦我有从内存数据存储切换到EF的经验。因此,拥有该选项总是很好,而不是依赖于特定于框架的API。
第四个原因是存储库为您提供的特定于域的API。而不是像db.Orders.Where(o => o.Category == "Food")
这样的东西,你有一个很好的方法repository.GetOrdersByCategory
。
另一个原因是您在一个地方拥有数据访问逻辑。没有重复。在上面的示例中,您可以在应用程序中有五个位置使用相同的查询按类别过滤订单。使用存储库,您将拥有单一方法,将在五个位置调用。考虑一下如果您的业务规则会发生变化?例如。您还需要检查类别是否有效。
还要记住 - 一旦有了UoW和Repository基类和接口,就可以在不同的项目中重用它们。