通用存储库使用EF 4.1有什么意义

Cod*_*mmr 145 unit-of-work repository-pattern entity-framework-4.1

随着我深入研究DbContext,DbSet和相关接口,我想知道为什么你需要围绕这些实现实现一个单独的"通用"存储库?

它看起来像DbContext和IDbSet做你需要的一切,并在DbContext中包含"工作单元".

我在这里遗漏了什么,或者似乎人们喜欢无缘无故地添加另一层依赖.

Lad*_*nka 202

你其实是对的.DbContext是工作单元模式IDbSet的实现,是存储库模式的实现.

存储库目前非常受欢迎并且过度使用.每个人都使用它们只是因为有很多关于为实体框架创建存储库的文章,但没有人真正描述与此决策相关的挑战.

使用存储库的主要原因通常是:

  • 从上层隐藏EF
  • 使代码更易于测试

第一个原因是某种建筑纯度和好主意,如果你让你的上层独立于EF,你可以稍后切换到其他持久性框架.你在现实世界中看过多少次这样的事情?这个原因使得使用EF变得更加困难,因为您的存储库必须公开许多附加功能,包括EF默认允许的内容.

同时,包装EF代码可以使您的代码更好地组织并遵循分离关注规则.对我来说,这可能是仓库和工作单位的唯一真正的优势,但你要明白,在与EF此规则将可能使你的代码更好的可维护性和更好的可读性,但在最初的努力来创建应用程序会高得多,对于较小的应用,这可能是不必要的复杂

第二个原因部分正确.EF的一大缺点是刚性架构很难被嘲笑,所以如果你想要对上层进行单元测试,你必须以某种方式包装EF以允许模拟它的实现.但这有许多其他后果,我在这里描述.

我关注Ayende的博客.如果你曾经使用NHibernate,你可能知道他的文章.这家伙最近写了几篇文章反对使用NHibernate使用存储库,但NHibernate更好的可模仿.

  • 如果我在我的业务层中直接使用DbSet和BdContext,我必须在那里以及我的DataLayer项目中引用EntityFramework.dll.仅这一点就告诉我它需要某种包装. (8认同)
  • 你可以模拟`IDbSet`,你也可以在派生的上下文中定义自定义接口,但这就是全部.一旦你的代码使用ChangeTracker,Entries或其他任何东西,它将需要很大的努力来包装它们. (3认同)
  • @chiccodoro:对.但是,一旦你的模拟类暴露了`IQueryable`或接受`Expression <>`作为参数,内部放入Linq-to-entities查询,你就是在模拟组件之外定义逻辑,副作用无法通过单元测试进行测试. (2认同)
  • downvote:incomplete - 在存储库接口后面抽象EF可以使完全相同的客户端代码在SL和WPF中运行. (2认同)

Ken*_*ett 21

我正在努力解决相同的问题,并且对EF层的单元测试的可模仿性很重要.但是我遇到了这篇伟大的文章,它解释了如何通过确保派生的DbContext实现了一个通用接口并公开IDbSet而不是DbSet来设置EF 4.1 DbContext是可模拟的.由于我使用的是Database First方法,因为我们的数据库已经存在,我只是修改了用于生成派生DbContext的T4模板,以生成它以返回IDbSet接口,以及从我的通用接口派生.这样就可以轻松地模拟整个事物,并且您不需要实现自己的工作单元或存储库模式.只写你的服务代码来使用你的通用接口,当你去到单元测试它,只是嘲笑与试验数据的通用接口,你是好去.

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/


小智 5

创建存储库的一个原因是,如果您决定从EntityFramework转移到其他地方,反之亦然,则可以隐藏DBSet和DbContext的实现.

例如,我使用的是NHibernate,并且在我的存储库类中包含了对该框架的所有调用.它们返回IEnumerable,因为它们是"通用的",我的存储库具有标准的CRUD操作(更新,删除等).我早就搬到了Entity Framework.这样做,我不需要在我的ViewModel类中更改任何内容,因为它们指向我的存储库 - 我只需要更改我的存储库内部.这使迁移时的生活更加轻松.

(我使用NHibernate是因为我们正在连接到ISeries,当时,没有使用EF和ISeries进行成本效益实现.唯一可用的是为IBM的DB2Connect支付12,000美元)