使用ORM实体框架的通用存储库模式+ UOW模式有什么优势

时间:2013-01-25 23:01:25

标签: entity-framework repository-pattern

让我们从两个引用开始,总结这个问题: “结束DbContext是一个漏洞的抽象。无论如何,你最终会在服务/控制器层中对EF产生某种依赖。” quote ref  第二个引用:

“DbContext Class

表示工作单元和存储库模式的组合,使您可以查询数据库并将更改组合在一起,然后将这些更改作为一个单元写回到商店。“MSDN

请不要说存储库模式允许您简单地换出数据库,但事实并非如此。有没有人用过成熟的应用程序做过这件事?另请注意,Repository模式不应该暴露IQueryable,我认为这只是另一种说法,你不相信与你合作的人。

我完全用于封装,代码覆盖/可测试性,但由于这种流行的回购模式为EF暴露了IQueryable,因此不再需要这种模式:

   public interface IRepository<T> where T : class
    {
    IQueryable<T> GetAll();
    T GetById(int id);
    IEnumerable<T> Get(Expression<Func<T, bool>> filter = null,Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(int id);
}

存储库模式与UOW模式相结合的唯一好处是: 1.轻松启用依赖注入模式以提高可测试性/代码覆盖率 2.封装外部集成存在的复杂性(对不同供应商,Web apis,数据库等的Web服务调用。)

那么我通过使用MyDbContext:DbContext类得到的封装是什么?我的ORM是抽象当然我通过工作的UOW和常见的查询(如添加和删除)得到控制器的一些统一性,但这真的值得付出努力。我不能只相信我的开发人员是统一的,当他们按照自己的方式做到这一点时,就不要让OCD得到它。并且由于控制器可以编写它想要的任何查询,这不会在单元测试面前飞行吗? AND(甚至更大的大写lol)如果我有第三方API来调用,我可以在MyDbContext类中为控制器访问它,这看起来就像是对控制器的另一个数据调用。

我再说一遍,为什么不直接使用ORM,它就是数据抽象!

以下是针对存储库模式的一些参数:

http://ayende.com/blog/4784/architecting-in-the-pit-of-doom-the-evils-of-the-repository-abstraction-layer

http://ayende.com/blog/3955/repository-is-the-new-singleton

http://lostechies.com/jimmybogard/2012/09/20/limiting-your-abstractions/

http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

这是存储库模式的正确参数(尽管不够令人信服): http://www.sapiensworks.com/blog/post/2012/10/10/Do-We-Need-The-Repository-Pattern.aspx

2 个答案:

答案 0 :(得分:6)

如果我再看到艾恩德的帖子,我想我会疯狂的。让我们慢慢来看看:

  1. Generic Repository的适用性有限。就个人而言,我只将它用于域名存储库,并且只有当我以序列化形式存储聚合根时。对于其他内容(阅读:视图模型,报告),我有一个存储库,专为满足这些模型的层需求而设计。

  2. IQueryable几乎是一个查询构建器。您没有告诉存储库如何来构建某些东西(IQUeryable),您只需要从中提出一些建议。如果您正在使用IQueryable,那么您已经在执行存储库工作的一部分(打破更高层的SRP)。同时暴露IQueryable意味着更高层必须知道用于创建查询的pocos /实体。如果您的老板决定从现在开始您将从Web服务获取数据,您会对所有那些洒在各处的IQueryable和ORM实体做些什么?或者RDBMS太慢所以让我们使用Document Db?是的,它可能会支持linq,但你确定你会定义相同的实体吗?

  3. 不要相信您的开发者。相信一个适当的架构,一个不混合层责任的架构,以及尊重SRP(单一责任原则)的架构。如果你正在进行设计,让我们说根据数据存储在数据库中的方式查看模型,而不是根据你在视图中的需要,你有一个紧耦合问题。

  4. 由于您不需要更改ORM或存储技术而不使用回购的原因是恕我直言的原因类似于:为什么使用DI容器或接口,这些类很少有机会改变,我们无论如何都可以做手动注射。

  5. 使用存储库意味着您无需关心如何以及从哪里检索模型。存储库公开了业务友好的语义(GetTopSellingProducts)。使用orm你必须构建查询(每个人都喜欢在linq中进行连接和子查询),了解实体,进行投影等。为什么更高层需要关注这些细节?这是'问,不说怎么'原则(j / k)

  6. 毕竟,这完全取决于可维护的代码,我希望我的代码易于理解。

答案 1 :(得分:3)

  

我再说一遍,为什么不直接使用ORM,它就是数据抽象!

数据抽象而非 数据抽象。

如果您需要将其切换出来,那就是抽象您的ORM。不是关于通用回购可以直接提供给DbContext的好东西。如果您确实需要切换EF和DbContext并且它是高度耦合的,则需要编辑使用DbContext的代码的所有部分,或者强制在您切换到的任何ORM上实现DbContext接口。

我认为在大多数应用程序中切换ORM的可能性很小,并且直接使用DbContext的便利性超过了与EF耦合的风险。但是,我仍然明白为什么有些人会根据应用要求和使用寿命来做这件事。