使用存储库模式来支持多个提供程序

时间:2011-05-18 21:17:36

标签: asp.net-mvc entity-framework design-patterns repository-pattern

嗯,不确定这是不是正确的标题,但基本上我在使用MVC应用程序中的存储库时遇到了很多问题,以至于您可以替换一组存储库,实现不同的数据存储技术,另一个。

例如,假设我想为我的应用程序使用Entity Framework。但是,我还希望在硬编码列表中实现一组测试数据。我希望有一组接口(IUserRepository,IProductRepository等 - 我们暂不谈论更通用的IRepository< T>)这两种方法都可以实例化。然后,使用(比方说)Ninject或Castle Windsor等依赖注入工具,我可以在实体框架提供程序(访问实际数据库)和测试提供程序(访问列表)之间来回切换。

简而言之,问题在于:

- 如果您要使用Entity Framework,您希望您的存储库返回IQueryable< SomeType>。

- 如果你打算使用硬编码列表,你不希望你的存储库返回IQueryable,因为它大大增加了开销,而且,Linq to Entities与Linq到Objects有很大不同,导致许多令人头疼的问题在两个提供商共有的代码中。

换句话说,我发现最好的方法是隔离存储库中所有依赖于EF的代码,以便存储库本身返回IEnumerable或IList或其他类似的东西 - 然后EF和其他一些技术都可以使用相同的库。因此,所有IQueryable都将包含在EF存储库中。这样,您可以将Linq to Entities与EF存储库一起使用,Linq to Objects与Test存储库一起使用。

然而,这种方法将大量的业务逻辑放入存储库中,并导致许多重复的代码 - 每个存储库中的逻辑都必须重复,即使实现方式有所不同。

存储库的整个想法作为这个非常薄的层并且只是连接到数据库然后丢失 - 存储库是业务逻辑的“存储库”以及数据存储连接。你不能只有查找,保存,更新等等。

我无法解决需要隔离提供程序相关代码和在集中位置拥有业务逻辑之间的这种差异。

有什么想法吗?如果有人能够指出一个解决这个问题的实现的例子,我将非常感激。 (我已经阅读了很多内容,但找不到任何专门讨论这些问题的内容。)

更新:

我想我开始觉得可能无法为不同的提供商换出存储库 - 例如,如果您打算使用Entity Framework,您只需要投入整个应用程序到实体框架。单元测试?我正在努力解决这个问题。到目前为止,我的做法是使用硬编码数据建立一个单独的存储库,并将其用于单元测试,以及在设置数据库之前测试应用程序本身。我想我将不得不寻找一个不同的解决方案,也许是一些嘲弄工具。

但后来提出了为什么要使用存储库的问题,特别是为什么要使用存储库接口。我正在研究这个问题。我认为确定最佳实践需要进行一些研究。

1 个答案:

答案 0 :(得分:14)

我能说什么?欢迎来到俱乐部...

您发现的是许多使用EFv4跟随“存储库繁荣”的开发人员遇到的问题。是的,这是问题,问题非常复杂。我多次讨论过这个问题:

单独的主题是使用存储库的原因:

基本上你提出的方法是一个解决方案,但你真的想要吗?在我看来,结果不是存储库,而是数据访问对象(DAO)暴露了大量的访问方法。 Martin Fowler的存储库定义是:

  

知识库在中间进行调解   行动的域和数据映射层   像内存中的域对象   采集。客户端对象构造   查询规范以声明方式和   将它们提交到Repository for   满足。可以添加对象   并从存储库中删除,如   他们可以从一个简单的集合   对象和映射代码   由Repository封装   进行适当的操作   在幕后。从概念上讲,   存储库封装了一组   对象持久存储在数据存储中   对他们进行的操作,   提供更面向对象的视图   持久层的。知识库   也支持的目标   实现清洁分离   域之间的单向依赖   和数据映射层。

我相信公开IQueryable比创建一个类似于存储过程时代的存储库的公共接口要好100倍 - 每个存储过程一个访问方法(固定查询)。

问题可以通过leaky abstraction的规则来概括。 IQueryable是数据库查询的抽象,但IQueryable提供的功能依赖于提供程序。不同的提供者=不同的功能集。

结论是什么?您是否因为测试而想要这样的架构?在这种情况下,开始使用前两个链接答案中提出的集成测试,因为在我看来这是最痛苦的方式。如果您采用您提出的方法,您仍应使用集成测试来验证您的存储库是否隐藏了所有与EF相关的逻辑和查询。