实体框架、应用程序层和关注点分离
我在我的应用程序中使用 Entity Framework 4.1 和 ASP.Net MVC 3。 MVC 提供表示层,中间库提供业务逻辑,实体框架充当数据层,我猜?
我可以将实体框架代码分成一组存储库类或其适当的变体,无论什么构成一个有价值的数据层,但我在解决我遇到的设计问题时遇到了困难。
如果多层方法的存在可以帮助我将关注点分开,那么按理说我对数据持久性的选择也不应该是表示层的关注点。问题是,通过使用实体框架,我基本上将我的应用程序与自动跟踪和保留实体更改的概念紧密耦合。
因此,假设在一个假设的世界中,我找到了不使用实体框架的理由并想将其换掉。一个设计良好的解决方案应该允许我在适当的层执行此操作,并且不会影响依赖层,但是因为所有代码都是在数据层跟踪对象更改的情况下编写的,所以我只能交换实体以类似方式工作的框架,例如 nHibernate。
如何使用实体框架,但不需要以假设数据层正在跟踪实体更改的方式编写代码?
对于那些在自己的场景中仍然想知道这个问题的人来说,更新:
Ayende Rahien 写了一篇很棒的文章驳斥了整个论点: http://ayende.com /blog/4567/the-false-myth-of-encapsulating-data-access-in-the-dal
I'm using the Entity Framework 4.1 and ASP.Net MVC 3 for my application. MVC provides the presentation layer, an intermediate library provides the business logic and the Entity Framework sort of acts as the data layer I guess?
I could separate the Entity Framework code into a set of repository classes, or an appropriate variation thereof, whatever constitutes a worthwhile data layer, but I'm having trouble resolving a design problem I have.
If the multi-layered approach exists to help me keep concerns separated, then it stands to reason that my choice of data persistence should also not be a concern of the presentation layer. The problem is that by using the Entity Framework, I'm basically tightly coupling my application to the notion that entity changes are tracked and persisted automatically.
As such, let's say in a hypothetical world I found a reason not to use the Entity Framework and wanted to swap it out. A well-designed solution should allow me to do this at the appropriate layer and not have dependent layers affected, but because all code is being written with the knowledge that the data layer tracks object changes, I would only be able to swap out the Entity Framework for something that works in a similar fashion, for example nHibernate.
How do I get to use the Entity Framework but not need to write my code in a way that assumes that entity changes are being tracked by the data layer?
UPDATE for those still wondering about this issue in their own scenarios:
Ayende Rahien wrote a great article shooting down this whole argument:
http://ayende.com/blog/4567/the-false-myth-of-encapsulating-data-access-in-the-dal
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你想继续这样下去,你应该放弃编程工作,去学习哲学。实体框架是持久性的抽象,并且存在泄漏抽象规则,该规则表示任何不平凡的抽象都在某种程度上漏水。
敏捷方法论带来了非常有趣的现象:不要为假设的情况做好准备。大多数时候,它只是镀金。每一次改变都有其成本。在项目后期更改持久层的成本很高,但也很少见。从客户的角度来看,没有理由在不需要这种改变的大多数项目中支付部分成本。如果我们更深入地讨论客户的观点,我们可以说他根本不应该为此付费,因为选择不好的 API 并在以后必须更换是开发人员/架构师的失败。定期重构您的代码,但仅限于添加客户想要的新功能所需的程度,否则您很难在市场上具有竞争力。这当然有一些例外:
现在解决您的问题。如果您想要如此高级的抽象,则不应将实体暴露给控制器。从业务层(甚至从存储库)公开 DTO,并向这些 DTO 添加 IsNew、IsModified、IsDeleted 等字段。现在,您的 UI 已与持久性完全分离,但您的架构要复杂得多,而且可能没有理由如此复杂 - 它的架构过度了。另一种方法可以简单地关闭跟踪(将
AsNoTracking()
添加到每个查询)和实体上的代理创建 (context.Configuration.ProxyCreationEnabled
) - 延迟加载将不起作用以及。这就像抛弃持久性框架为您提供的大部分功能。也有其他观点。我建议您阅读 Ayende 最近关于存储库的帖子以及他对 Sharp 架构的评论。
If you want to continue this way you should give up programming job and go to study philosophy. Entity framework is abstraction of persistence and there is a rule of Leaky abstraction which says that any non-trivial abstraction is to some degree leaky.
Agile methodologies come with really interesting phenomenon: Do not prepare for hypothetical situations. The most of the time it is just Gold plating. Each change has its cost. Changing persistence layer later in the project is costly but it is also very rare. From customer perspective there is no reason to pay part of these costs in the most of projects where this change is not needed. If we discus customer perspective more deeply we can say that he should not pay for that at all because choosing bad API which has to be replaced later on is failure of developers / architects. Refactor your code regularly but only to the point which is needed for adding new features which customer wants otherwise you can hardly be competitive on the market. This of course has some exceptions:
Now to your problem. If you want such high level abstraction you should not expose entities to your controller. Expose DTOs from the business layer (or even from repositories) and add fields like IsNew, IsModified, IsDeleted to those DTOs. Now your UI is completely separated from the persistence but your architecture is much more complex and there is probably no reason for such complexity - it is over architected. Another way can be simply turning off tracking (add
AsNoTracking()
to each query) and proxy creation on your entities (context.Configuration.ProxyCreationEnabled
) - lazy loading will not work as well. That's like throwing away most of features persistence frameworks offer to you.There are also other points of view. I recommend you reading Ayende's recent posts about repository and his comments to Sharp architecture.
简短的回答?你不知道。您可以关闭 EF 的跟踪,然后不用担心它,但仅此而已。
如果您要编写表示层并希望自动跟踪和保留更改,那么无论您用什么替换 EF 都必须这样做。您不能将其替换为不能自动跟踪和保留更改并只是期望事情继续工作的东西。这就像将一个依赖 TCP/IP 连接进行双工通信的系统,将其交换为 HTTP 连接(就 HTTP 的本质而言,它并不是真正的双工),并期望事情以相同的方式工作。事实并非如此。
如果您希望能够将持久层替换为其他内容并且不必更改任何其他内容,那么您需要将 EF(或其他内容)包装在您自己的自定义代码中以提供您想要的功能。然后,您必须为您交换到的任何内容未提供的任何内容提供实现。
这是可行的,但是对于一个实际上很少发生的问题来说,这将是一项巨大的工作。它还会增加项目的额外复杂性。拉迪斯拉夫一针见血:不值得抽象这么远。
Short answer? You don't. You could turn off EF's tracking and then not worry about it, but that's about it.
If you're going to write your presentation layer with the expectation that changes are being tracked and persisted automatically, then whatever you replace EF with has to do that. You can't swap it out for something that doesn't track and persist changes automatically and just expect things to keep working. That'd be like taking a system that relies on a TCP/IP connection for duplex communication, swapping it to a HTTP connection (which by the nature of HTTP isn't really duplex) and expect things to work the same way. It doesn't.
If you want to be able to swap out your persistence layer for something else and not have to change anything else, then you need to wrap EF (or whatever) in your own custom code to provide the functionality you want. Then you have to provide implementations for anything not provided by whatever you swap to.
This is doable, but it's going to be an awful lot of work for a problem that very rarely actually happens. It's also going to add extra complexity to the project. Ladislav is bang on: it's not worth abstracting this far.
如果您担心可能会换出 EF,您应该实现存储库模式和普通 POCOS。
Codeplex 上有一个很棒的项目,它涵盖了域驱动设计(包括文档)。看看那个。
http://microsoftnlayerapp.codeplex.com/
You should implement the repository pattern and plain POCOS if you are concerned about potentially swapping out EF.
There is a great project on Codeplex that goes over Domain Driven design including documentation. Take a look at that.
http://microsoftnlayerapp.codeplex.com/
请在阅读完 Microsoft n-layer 项目后,阅读 ayenede 的博客。
Mr.ayende 发布了有关 Microsoft n-layer 项目优缺点的系列文章。
Please after reading Microsoft n-layer project, read ayenede's weblog.
Mr.ayende posted series posts about advantage and disadvantage Microsoft n-layer project.