使用存储库模式来支持多个提供者 [英] Using the repository pattern to support multiple providers

查看:23
本文介绍了使用存储库模式来支持多个提供者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Well, not sure if that's exactly the right title, but basically I have been having a lot of problems using repositories in MVC applications in such a way that you can substitute one set of repositories, implementing a different data storage technology, for another.

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

For example, suppose I want to use Entity Framework for my application. However, I also want to have a set of test data implemented in hard-coded Lists. I would like to have a set of interfaces (IUserRepository, IProductRepository, etc. -- let's not talk about a more generic IRepository<T> for now) that both approaches can instantiate. Then, using (say) a Dependency Injection tool such as Ninject or Castle Windsor, I can switch back and forth between the entity framework provider (accessing the actual database) and the test provider (accessing the lists).

简而言之,问题在于:

-- 如果您打算使用实体框架,您希望您的存储库返回 IQueryable.

-- If you are going to use Entity Framework, you want your repositories returning IQueryable<SomeType>.

-- 如果您打算使用硬编码列表,您不希望您的存储库返回 IQueryable,因为它极大地增加了开销,而且,Linq to Entities 与 Linq to Objects 有很大不同,导致许多头痛在两个提供程序通用的代码中.

-- If you are going to use hard-coded lists, you do NOT want your repositories returning IQueryable, because it adds hugely to the overhead, and plus, Linq to Entities is significantly different from Linq to Objects, causing many headaches in the code that is common to both providers.

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

In other words, I have found that the best approach isolates all the EF-dependent code within the repositories, so that the repositories themselves return IEnumerable or IList or some such -- then both EF and some other technology can use the same repositories. Thus, all the IQueryable's would be contained WITHIN the EF repositories. That way, you can use Linq to Entities with the EF repositories, and Linq to Objects with the Test repositories.

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

Yet this approach puts an enormous amount of the business logic into the repositories, and results in much duplicated code -- the logic has to be duplicated in each of the repositories, even if the implementations are somewhat different.

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

The whole idea of the repositories as this layer that is very thin and just connects to the database is then lost -- the repositories are "repositories" of business logic as well as of data store connectivity. You can't just have Find, Save, Update, etc.

我一直无法解决需要隔离依赖于提供者的代码和将业务逻辑放在一个集中位置之间的差异.

I've been unable to resolve this discrepancy between needing to isolate provider-dependent code, and having business logic in a centralized location.

有什么想法吗?如果有人可以向我指出解决此问题的实现示例,我将不胜感激.(我已经阅读了很多,但找不到任何专门讨论这些问题的内容.)

Any ideas? If anyone could point me to an example of an implementation that addresses this concern, I would be most appreciative. (I've read a lot, but can't find anything that specifically talks about these issues.)

更新:

我想我开始觉得可能无法将存储库替换为不同的提供者——例如,如果您要使用实体框架,您只需要投入整个应用程序到实体框架.单元测试?我正在为此而苦苦挣扎.到目前为止,我的做法是使用硬编码数据设置单独的存储库,并将其用于单元测试,以及在设置数据库之前测试应用程序本身.我想我将不得不寻找不同的解决方案,也许是一些模拟工具.

I guess I'm starting to feel that it's probably not possible to have repositories that can be swapped out for different providers -- that if you are going to use Entity Framework, for example, you just have to devote your whole application to Entity Framework. Unit tests? I'm struggling with that. My practice to this point has been to set up a separate repository with hard-coded data and use that for unit testing, as well as to test the application itself before the database is set up. I think I will have to look to a different solution, perhaps some mocking tool.

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

But then that raises the question of why use repositories, and especially why use repository interfaces. I'm working on this. I think determining the best practice is going to take a bit of research.

推荐答案

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

What I can say? Welcome to the club ...

您发现的是许多遵循 EFv4存储库热潮"的开发人员遇到的问题.是的,这就是问题所在,而且问题确实很复杂.我讨论过几次:

What you found is problem reached by many developers who followed "repository boom" with EFv4. Yes it is the problem and the problem is really complex. I discussed this several times:

单独的主题是为什么使用存储库:

Separate topic is why to use repositories:

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

Basically your proposed way is a solution but do you really want it? In my opinion the result is not repository but the Data Access Object (DAO) exposing plenty of access methods. Repository definition by Martin Fowler is:

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

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.

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

I believe exposing IQueryable fulfils this 100 times better then creating a public interface similar to repositories from Stored procedures era - one access method per stored procedure (fixed query).

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

The problem can be summarized by the rule of leaky abstraction. IQueryable is an abstraction of the database query but the features provided by IQueryable are dependent on the provider. Different provider = different feature set.

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

What is a conclusion? Do you want such architecture because of testing? In such case start using integration tests as proposed in first two linked answers because in my opinion it is the lest painful way. If you go with your proposed approach you should still use integration tests to verify your repositories hiding all EF related logic and queries.

这篇关于使用存储库模式来支持多个提供者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆