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

Cyn*_*hia 14 asp.net-mvc design-patterns entity-framework 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实体与EF存储库一起使用,将Linq添加到具有测试存储库的对象.

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

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

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

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

更新:

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

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

Lad*_*nka 14

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

您发现的是许多开发人员使用EFv4跟随"存储库热潮"所遇到的问题.是的,这是问题,问题非常复杂.我多次讨论过这个问题:

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

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

存储库在域和数据映射层之间进行调解,其作用类似于内存中的域对象集合.客户端对象以声明方式构造查询规范,并将它们提交给Repository以满足要求.可以从简单的对象集合中向对象添加对象或从对象库中删除对象,并且由存储库封装的映射代码将在后台执行适当的操作.从概念上讲,存储库封装了持久存储在数据存储中的对象集以及对它们执行的操作,从而提供了更加面向对象的持久层视图.存储库还支持在域和数据映射层之间实现清晰分离和单向依赖的目标.

我认为暴露IQueryable比使用存储过程时代创建类似于存储库的公共接口 - 每个存储过程一种访问方法(固定查询)更好地实现了100倍.

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

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