通用库与EF 4.1有什么关系
当我更深入地了解DbContext,DbSet和相关的接口时,我想知道为什么你需要围绕这些实现实现一个单独的“Generic”存储库?
它看起来像DbContext和IDbSet做你需要的一切,包括DbContext里面的“工作单位”。
我在这里错过了什么东西,或者似乎人们喜欢没有理由再添加一层依赖。
你其实是对的。 DbContext
是工作模式单元的实现, IDbSet
是存储库模式的实现。
存储库目前非常流行和过度使用。 每个人都使用它们只是因为有几十篇关于为实体框架创建存储库的文章,但没有人真正描述与这个决定相关的挑战。
使用仓库的主要原因通常是:
- 从上层隐藏EF
- 使代码更好地测试
第一个原因是某种建筑的纯粹性和好主意,如果你让你的上层独立于EF,你可以在以后转换到其他的持久性框架。 你在现实世界中看过多少次这样的事情? 这个原因使得使用EF更加困难,因为你的仓库必须公开很多额外的功能,包装了EF默认允许的功能。
同时包装EF代码可以使您的代码更好地组织和遵循分离关注规则。 对我来说,这可能是存储库和工作单元的唯一真正的优势,但是你必须明白,遵循这个与EF的规则可能会使你的代码更好的可维护性和更好的可读性,但在最初的努力来创建你的应用程序将更高,对于较小的应用程序,这可能是不必要的复杂性
第二个原因是部分正确的。 EF的一个很大的缺点就是刚性架构难以嘲讽,所以如果你想要对上层进行单元测试的话,你必须用EF来封装EF来嘲笑它的实现。 但是这里有我在这里描述的许多其他的后果。
我遵循Ayende的博客 。 如果你曾经使用NHibernate,你可能会知道他的文章。 这家伙最近写了几篇文章反对使用NHibernate的存储库,但NHibernate是更好的嘲笑。
我正在为同样的问题苦苦挣扎,EF层的单元测试的可模拟性非常重要。 但是我碰到了这篇很棒的文章,它解释了如何通过确保派生的DbContext实现一个通用接口并暴露IDbSet而不是DbSet的方式来设置EF 4.1 DbContext为可嘲弄的。 由于我使用的是数据库优先的方法,因为我们的数据库已经存在,所以我只是修改了用于生成我的派生DbContext的T4模板,以生成它来返回IDbSet接口,以及从我的通用接口派生。 这样整个事情就可以很容易地被嘲弄,而且你不需要实现你自己的工作单元或者存储库模式。 只要编写你的服务代码来使用你的通用接口,当你去单元测试时,只需要用特定的测试数据来模拟通用接口,就可以了。
创建存储库的一个原因是你可以隐藏DBSet和DbContext的实现,如果你决定从EntityFramework转移到其他的,反之亦然。
例如,我使用的是NHibernate,并将所有对这个框架的调用都包含在我的仓库类中。 他们返回IEnumerable获取“通用”,我的仓库有标准的CRUD操作(更新,删除等)。 我早已转移到实体框架。 这样做后,我不需要改变我的ViewModel类或其他任何东西,因为它们指向我的存储库 – 我只需要改变我的存储库的内部。 迁移时,这让生活变得更加轻松。
(我使用了NHibernate是因为我们连接到了ISeries,而且当时没有使用EF与ISeries的成本情感实现,唯一可用的是向IBM支付$ 12,000的DB2Connect)