具体服务应该依赖于具体的存储库或接口吗?

时间:2014-05-09 18:20:15

标签: c# entity-framework dependency-injection repository-pattern

在使用ASP.net MVC和Entity Framework时,我一直在努力实现存储库和服务模式。

我理解存储库模式的目的以及它如何帮助测试并使数据层可以互换。但是,实体框架已经是工作模式的存储库/单元。我见过的存储库模式的每个实现都剥离了EF的有用功能,或者实现了一个使纯粹主义者蠕动的IQueryable<T>属性。

如果我正在为我的服务层编写接口,那么实现这些服务的具体版本是有原因的,我不应该直接在服务中使用Entity Framework作为我的数据层(而不是将其包装在存储库中)工作单元模式和注入依赖)?例如:我不能创建一个IService接口,然后创建一个具体的EfService(实体框架)或NhService(NHibernate版本)实现?

然后,我可以使用我的IoC容器注入所需的服务和数据上下文。


以下是根据谢尔盖的评论我提出的一个例子:https://github.com/sweeperq/Monona

该模式是如何实现的?

1 个答案:

答案 0 :(得分:3)

我总是使用存储库接口。

第一个原因是可测试性 - DbContextDbSet<T>难以模拟。因此,即使可能,服务的单元测试也变得非常困难。

第二个原因是EF公开IQueryable<T>。它使数据访问逻辑遍布整个应用程序,这违反了SRP并使修复问题更难。

第三个原因可能不是很重要 - 切换接口实现的能力 - 不仅可以使用真实对象和模拟,还可以使用不同的数据访问框架。你总是认为 - “不,我肯定会坚持EF”。但在现实世界中,由于性能问题和易于开发,我有切换到Dapper的经验。一旦我有从内存数据存储切换到EF的经验。因此,拥有该选项总是很好,而不是依赖于特定于框架的API。

第四个原因是存储库为您提供的特定于域的API。而不是像db.Orders.Where(o => o.Category == "Food")这样的东西,你有一个很好的方法repository.GetOrdersByCategory

另一个原因是您在一个地方拥有数据访问逻辑。没有重复。在上面的示例中,您可以在应用程序中有五个位置使用相同的查询按类别过滤订单。使用存储库,您将拥有单一方法,将在五个位置调用。考虑一下如果您的业务规则会发生变化?例如。您还需要检查类别是否有效。

还要记住 - 一旦有了UoW和Repository基类和接口,就可以在不同的项目中重用它们。