【问题标题】:Entity Framework, application layers and separation of concerns实体框架、应用层和关注点分离
【发布时间】:2011-05-11 17:06:24
【问题描述】:

我正在为我的应用程序使用 Entity Framework 4.1 和 ASP.Net MVC 3。 MVC 提供表示层,中间库提供业务逻辑,我猜 Entity Framework 有点充当数据层?

我可以将实体框架代码分成一组存储库类或其适当的变体,无论构成一个有价值的数据层,但我在解决我遇到的设计问题时遇到了麻烦。

如果存在多层方法来帮助我将关注点分开,那么我对数据持久性的选择也不应该是表示层关注的问题。问题是通过使用实体框架,我基本上将我的应用程序与自动跟踪和持久化实体更改的概念紧密耦合。

因此,假设在一个假设的世界中,我找到了不使用实体框架的理由并想将其换掉。一个设计良好的解决方案应该允许我在适当的层执行此操作并且不会影响依赖层,但是因为所有代码都是在数据层跟踪对象更改的知识下编写的,所以我只能换出实体以类似方式工作的框架,例如 nHibernate。

如何使用实体框架,但不需要以假设数据层正在跟踪实体更改的方式编写代码?

对于那些在他们自己的场景中仍然想知道这个问题的人的更新:
Ayende Rahien 写了一篇很棒的文章驳斥了整个论点: http://ayende.com/blog/4567/the-false-myth-of-encapsulating-data-access-in-the-dal

【问题讨论】:

    标签: entity-framework orm architecture entity-framework-4.1 separation-of-concerns


    【解决方案1】:

    如果你想继续这样下去,你应该放弃编程工作,去学习哲学。实体框架是持久性的抽象,有一条Leaky abstraction 的规则表示任何非平凡的抽象在某种程度上都是有漏洞的。

    敏捷方法伴随着非常有趣的现象:不要为假设的情况做准备。大多数时候它只是Gold plating。每一次改变都有它的代价。在项目后期更改持久层的成本很高,但也很少见。从客户的角度来看,在大多数不需要这种改变的项目中,没有理由支付部分成本。如果我们更深入地讨论客户的观点,我们可以说他根本不应该为此付费,因为选择稍后必须更换的糟糕 API 是开发人员/架构师的失败。定期重构您的代码,但仅限于添加客户想要的新功能所需的程度,否则您几乎无法在市场上具有竞争力。这当然有一些例外:

    • 客户想要(或架构出于任何原因需要它并且客户同意它)这样的抽象。在这种情况下,您必须考虑它并为此类更改定义开放的架构。
    • 这是一种爱好或开源项目,您可以在其中做自己想做的事,因为它不受某些资源的限制

    现在解决您的问题。如果您想要如此高级别的抽象,您不应该将实体暴露给您的控制器。从业务层(甚至从存储库)公开 DTO,并将 IsNew、IsModified、IsDeleted 等字段添加到这些 DTO。现在您的 UI 与持久性完全分离,但您的架构要复杂得多,而且可能没有理由导致这种复杂性 - 它过度架构。另一种方法是简单地关闭跟踪(在每个查询中添加AsNoTracking())和在您的实体上创建代理(context.Configuration.ProxyCreationEnabled)——延迟加载也不起作用。这就像抛弃了持久性框架为您提供的大部分功能。

    还有其他观点。我建议您阅读 Ayende's 最近关于存储库和他的 cmets 到 Sharp 架构的帖子。

    【讨论】:

    • 只是想补充一点,所有 ORM 还共享大量难以替换的差异。最重要的区别包括级联删除行为、急切加载行为、linq 行为(例如,必须在使用 ef 跳过之前执行命令)、存储的 proc/view 行为、ad-hoc sql 行为、即使使用 linq 的投影行为。神话般的可交换 ORM 层不存在。无论如何,你要做很多工作。
    • 很好的答案!老实说,有时候我只需要把这些东西从别人身上弹开来让我放心。
    • 这对于单个应用程序来说是一个很好的观点,但是如果您计划编写多个应用程序并且它们都应该使用相同的基本概念(可能还有代码 - 也就是库)怎么办。然后事情变得复杂,你不能只是“建立客户想要的东西”(反正他也不知道)。
    【解决方案2】:

    简短回答?你没有。您可以关闭 EF 的跟踪,然后不用担心,仅此而已。

    如果您要编写表示层并期望自动跟踪和持久化更改,那么无论您用什么替换 EF,都必须这样做。你不能把它换成不能自动跟踪和持续变化的东西,只是期望事情继续工作。这就像采用一个依赖 TCP/IP 连接进行双工通信的系统,将其交换为 HTTP 连接(从 HTTP 的性质来看,它并不是真正的双工)并期望事情以相同的方式工作。没有。

    如果您希望能够将持久层换成其他东西而不必更改其他任何东西,那么您需要将 EF(或其他)包装在您自己的自定义代码中以提供您想要的功能。然后你必须为你所交换的任何东西都没有提供实现。

    这是可行的,但对于一个很少实际发生的问题,这将是一项非常艰巨的工作。它还将为项目增加额外的复杂性。拉迪斯拉夫大获成功:不值得抽象到这一步。

    【讨论】:

      【解决方案3】:

      如果您担心可能会换出 EF,则应实施存储库模式和普通 POCOS。

      Codeplex 上有一个很棒的项目,它涵盖了领域驱动设计,包括文档。看看那个。

      http://microsoftnlayerapp.codeplex.com/

      【讨论】:

      • 在我看来,这似乎违背了持久无知的目的。我的控制器层不应该关心我使用的是 ORM 还是存储库模型。
      • 如果这两个东西没有提供相同的功能,那么你的控制器层绝对应该关心。自动跟踪和持久化更改的东西需要与不自动跟踪和持久化的东西完全不同的控制器逻辑。
      • 你是对的,正如我所说,你可以使用普通的 POCOS 并将它们作为 DTO 传递——它们应该是持久的无知。存储库模式不会强迫您使用任何特定的数据访问方法。
      【解决方案4】:

      请阅读微软n层项目后,阅读ayenede's weblog. Mr.ayende 发布了一系列关于微软 n 层项目的优势和劣势的帖子。

      【讨论】:

        猜你喜欢
        • 2010-12-14
        • 1970-01-01
        • 2010-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-30
        • 2012-01-12
        相关资源
        最近更新 更多