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

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

问题描述

嗯,不知道这是否是正确的标题,但是基本上我在MVC应用程序中使用存储库有很多问题,可以用一组存储库替代一个不同的数据存储技术另一个。



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



简而言之,这里是问题:



- 如果您要使用Entity Framework,则希望您的存储库返回IQueryable& SOMETYPE取代。



- 如果您要使用硬编码列表,则不希望您的存储库返回IQueryable,因为它增加了大量的开销,并加上Linq实体与Linq对象显着不同,导致两个提供程序通用代码中的许多头痛。



换句话说,我发现最好的方法是将所有存储库中的依赖EF的代码,使得存储库本身返回IEnumerable或IList或其他一些,那么EF和其他一些技术可以使用相同的存储库。因此,所有的IQueryable将被包含在EF存储库中。这样,您可以使用Linq到实体与EF存储库,以及Linq对象与测试存储库。



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



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



我无法解决需要隔离与供应商相关的代码和进行业务的差异逻辑在一个集中的位置。



任何想法?如果有人可以指出一个解决这个问题的实施的例子,我将非常感激。 (我读了很多,但找不到任何具体谈到这些问题的东西。)



更新:


$ b $我想我开始觉得可能不可能有不同的提供商可以交换存储库 - 例如,如果你要使用实体框架,那么你只需要投入你的整个应用于实体框架。单元测试?我正在努力。我到现在的做法是建立一个单独的硬件编码数据库,并将其用于单元测试,以及在数据库建立之前对应用程序本身进行测试。我想我将不得不考虑一个不同的解决方案,也许是一些嘲弄的工具。



但是,这提出了为什么使用存储库,特别是为什么使用存储库接口的问题。我在努力工作我认为确定最佳做法是要进行一些研究。

解决方案

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



您发现的是许多开发人员遇到的与EFv4仓库繁荣的问题。是的,这是问题,问题真的很复杂。我几次讨论过:





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





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

存储库介于
域和数据映射层之间,代表
像内存中的域对象
集合。客户端对象以声明方式构造
查询规范,并将
提交给Repository,以满足
的要求。对象可以被添加到
并从Repository中删除,如
,它们可以通过
对象的简单集合,并且存储库封装的映射代码

在幕后执行相应的操作
。在概念上,
存储库封装了一组
对象,持久存储在数据存储中,
执行对它们的操作,
提供了一个更面向对象的视图
持久层存储库
还支持
的目标,实现一个干净的分离,并且

和数据映射层之间的单向依赖。




我相信曝光 IQueryable 实现了这100倍,然后创建一个类似于存储过程时代的存储库的公共接口 - 一个访问方法每个存储过程(固定查询)。



可以按照泄漏的规则总结问题抽象 IQueryable 是数据库查询的抽象,但由 IQueryable 提供的功能取决于提供者。不同的提供者=不同的功能集。



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


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.

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).

In a nutshell, here's the problem:

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

-- 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.

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.)

UPDATE:

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 ...

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:

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:

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.

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).

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.

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天全站免登陆