通用存储库与 EF 4.1 的意义何在
当我深入研究 DbContext、DbSet 和相关接口时,我想知道为什么您需要围绕这些实现实现一个单独的“通用”存储库?
看起来 DbContext 和 IDbSet 可以完成您需要的一切,并在 DbContext 中包含“工作单元”。
我是否在这里遗漏了一些东西,或者人们似乎喜欢无缘无故地添加另一层依赖。
As i dig deeper in to the DbContext, DbSet and associated interfaces, I am wondering why you would need to implement a separate "Generic" Repository around these implementations?
It looks like DbContext and IDbSet do everything you need and include the "Unit Of Work" inside DbContext.
Am I missing something here or does it seem people enjoy adding another layer of dependency for no reason.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你其实是对的。
DbContext
是工作单元模式的实现,IDbSet
是存储库模式的实现。存储库目前非常流行并且被过度使用。每个人都使用它们只是因为有数十篇关于为实体框架创建存储库的文章,但没有人真正描述与此决定相关的挑战。
使用存储库的主要原因通常是:
第一个原因是某种架构的纯粹性和好主意,如果您使上层独立于 EF,您可以稍后切换到其他持久性框架。你在现实世界中见过多少次这样的事情?这个原因使得使用 EF 变得更加困难,因为您的存储库必须公开许多附加功能,这些功能包含 EF 默认允许的功能。
同时,包装 EF 代码可以使您的代码更好地组织并遵循关注点分离规则。对我来说,这可能是存储库和工作单元的唯一真正优势,但您必须了解,使用 EF 遵循此规则可能会使您的代码更好地维护和更好地阅读,但在创建应用程序的最初努力中会更高,对于较小的应用程序,这可能会带来不必要的复杂性。
第二个理由部分正确。 EF 的一大缺点是刚性架构,很难模拟,因此如果您想对上层进行单元测试,则必须以某种方式包装 EF 以允许模拟其实现。但这会产生许多其他后果,我在此处描述。
我关注 Ayende 的博客。如果您曾经使用过 NHibernate,您可能会知道他的文章。这个人最近写了几篇反对使用 NHibernate 存储库的文章,但 NHibernate 的可模拟性要好得多。
You are actually right.
DbContext
is an implementation of the unit of work pattern andIDbSet
is an implementation of the repository pattern.Repositories are currently very popular and overused. Everybody use them just because there are dozens of articles about creating repository for entity framework but nobody actually describes challenges related to this decision.
Main reasons for using repository are usually:
The first reason is some kind of architectonic purity and great idea that if you make your upper layers independent on EF you can later on switch to other persistence framework. How many times did you see such thing in the real world? This reason makes working with EF much harder because your repository must expose a lot of additional features wrapping what EF allows by default.
In the same time wrapping EF code can keep your code better organized and following Separation of concern rule. For me this can be the only real advantage of repository and unit of work but you have to understand that following this rule with EF will maybe make your code better maintainable and better readable but in the initial effort to create your application will be much higher and for smaller applications this can be unnecessary complexity.
The second reason is partially correct. The big disadvantage of EF is rigid architecture which can be hardly mocked so if you want to unit test upper layer you must wrap EF somehow to allow mocking its implementation. But this has many other consequences which I described here.
I follow Ayende's blog. If you ever used NHibernate you probably know his articles. This guy recently wrote several articles against using repository with NHibernate but NHibernate is much better mockable.
我正在努力解决同样的问题,EF 层单元测试的可模拟性非常重要。但我遇到了这篇很棒的文章,它解释了如何通过确保派生的 DbContext 实现通用接口并公开 IDbSet 而不是 DbSet 来将 EF 4.1 DbContext 设置为可模拟的。由于我使用数据库优先方法,因为我们的数据库已经存在,所以我只是修改了用于生成派生 DbContext 的 T4 模板,以生成它以返回 IDbSet 接口,并从我的通用接口派生。这样,整个事情就可以很容易地被模拟,并且您不需要实现自己的工作单元或存储库模式。只需编写服务代码来使用通用接口,当您对其进行单元测试时,只需使用特定的测试数据模拟通用接口即可。
http:// /refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/
I am struggling with the same issues, and mockability for unit testing of the EF layers is important. But I ran across this great article which explains how to set up the EF 4.1 DbContext to be mockable by making sure your derived DbContext implemented a generic interface and exposes IDbSet rather than DbSet's. Since I am using a Database First approach, because our database already exists, I simply modified the T4 templates used to generate my derived DbContext to generate it to return IDbSet interfaces, as well as derive from my generic interface. That way the entire thing can be easily mocked, and you don't need to implement your own Unit Of Work or repository pattern. Just write your service code to consume your generic interface, and when you go to unit test it, just mock the generic interface with specific test data and you are good to go.
http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/
创建存储库的原因之一是,如果您决定从 EntityFramework 迁移到其他框架,则可以隐藏 DBSet 和 DbContext 的实现,反之亦然。
例如,我使用 NHibernate,并将对该框架的所有调用包装在我的存储库类中。它们返回 IEnumerable 因为它们的获取是“通用的”,并且我的存储库具有标准的 CRUD 操作(更新、删除等)。我早已转向实体框架。这样做后,我不需要更改 ViewModel 类或其他类中的任何内容,因为它们指向我的存储库 - 我只需要更改存储库的内部。这使得迁移时的生活变得更加轻松。
(我使用 NHibernate 是因为我们要连接到 ISeries,并且当时没有将 EF 与 ISeries 结合使用的成本有效的实现。唯一可用的方法是向 IBM 支付 12,000 美元以获得其 DB2Connect)
One reason for creating the repository is so you can hide the implementation of DBSet and DbContext if you decide to move from EntityFramework to something else or vice versa.
For example, I was using NHibernate and I wrapped all of the calls to that framework inside my repository classes. They return IEnumerable for their gets to be "generic" and my repositories have the standard CRUD operations (update, delete, etc). I have long since moved to Entity Framework. Upon doing so, I did not need to change anything in my ViewModel classes or beyond because they pointed to my repository--I only needed to change the inside of my repository. This made life much easier when migrating.
(I used NHibernate because we are connecting to the ISeries, and at the time, there were no cost affective implementations using EF with the ISeries. The only one available was to pay $12,000 to IBM for their DB2Connect)