Entity Framework,应用层和关注点分离

8
我正在使用Entity Framework 4.1和ASP.Net MVC 3开发应用程序。MVC提供了表示层,中间库提供业务逻辑,而Entity Framework则充当数据层。
我可以将Entity Framework代码分离成一组存储库类或一个合适的变体,无论哪种方式都构成了一个有价值的数据层,但我遇到了解决设计问题的困难。
如果多层方法存在以帮助我保持关注点分离,那么我的数据持久性选择也不应该是表示层的关注点。问题在于,通过使用Entity Framework,我基本上将应用程序与跟踪实体更改并自动持久化的概念紧密耦合起来。
因此,在假设的世界中,如果我找到了不使用Entity Framework并希望进行交换的原因,一个设计良好的解决方案应该允许我在适当的层进行这样的更改,而不会影响其他相关的层。但是,由于所有代码都是根据数据层跟踪对象更改的知识编写的,因此我只能将Entity Framework替换为以类似方式工作的东西,例如nHibernate。
我如何使用Entity Framework而不需要编写假定数据层正在跟踪实体更改的代码?
对于仍然关心自己情况的人的更新:
Ayende Rahien撰写了一篇精彩的文章,打破了整个论点: http://ayende.com/blog/4567/the-false-myth-of-encapsulating-data-access-in-the-dal
4个回答

9
如果您想继续这条路,您应该放弃编程工作并去学习哲学。实体框架是持久性的抽象,有一个泄漏的抽象规则,它说任何非平凡的抽象在某种程度上都是泄漏的。
敏捷方法带来了一个非常有趣的现象:不要为假设的情况做准备。大多数情况下这只是过度设计。每一次变更都有其代价。在项目后期更改持久层是昂贵的,但这也非常罕见。从客户的角度来看,在大多数项目中,这种变化是不必要的,因此没有理由支付其中的部分成本。如果我们更深入地讨论客户的观点,我们可以说,他根本不应该为此付费,因为选择需要后续替换的糟糕API是开发人员/架构师的失败。定期重构您的代码,但仅到添加客户需求所需的程度,否则您很难在市场上竞争。当然,这里有一些例外:
  • 客户需要(或架构要求出于任何原因并且客户同意)这种抽象。在这种情况下,您必须考虑到它,并定义开放的架构以进行此类更改。
  • 这是一项业余爱好或开源项目,您可以做您想做的事情,因为它不受某些资源的限制

现在来看看您的问题。如果您想要这样的高级抽象,则不应将实体暴露给控制器。从业务层(甚至从存储库)公开DTO,并向这些DTO添加字段,例如IsNew、IsModified、IsDeleted。现在,您的UI完全与持久性分离,但您的架构更加复杂,而且可能没有这种复杂性的理由-它被过度设计了。另一种方法可以简单地关闭跟踪(对每个查询添加AsNoTracking())和代理创建(context.Configuration.ProxyCreationEnabled)-惰性加载也将无法工作。这就像扔掉持久性框架为您提供的大多数功能。

还有其他观点。我建议您阅读Ayende最近关于存储库的帖子及其对Sharp架构的评论。


1
只是想补充一下,所有ORM也都有很多不同之处,很难进行交换。我能想到的不同之处包括级联删除行为、急切加载行为、linq行为(例如必须在ef中按顺序执行order before skip in take),存储过程/视图行为、即席SQL行为,甚至是使用linq的投影行为。神话般的可交换ORM层并不存在。无论如何,你都需要做很多工作。 - John Farrell
好答案!老实说,有时我只需要和别人交流一下这些东西,来让自己感到放心。 - Nathan Ridley
这是对于单个应用程序的一个好观点,但如果您计划编写多个应用程序,并且它们都应该使用相同的基本概念(也许是代码 - 即库),那么事情就会变得复杂起来,您不能只是“构建客户想要的”(他也不知道)。 - Marc

2
简短回答?你不能。你可以关闭EF的跟踪功能,然后不用担心它,但仅此而已。
如果您打算使用期望自动跟踪和持久化更改的方式编写演示层,则无论您用什么替换EF都必须这样做。您不能将其替换为不自动跟踪和持久化更改的内容,并期望事情继续正常工作。这就像将依赖于TCP/IP连接进行双工通信的系统更换为HTTP连接(根据HTTP的性质,它并不是真正的双工),并期望事情保持同样的方式。那是不可能的。
如果您想能够将持久性层替换为其他东西而不必更改其他任何内容,则需要在自己的自定义代码中包装EF(或其他内容)以提供所需的功能。然后,您必须为任何未提供的内容提供实现。
这是可行的,但对于很少发生的问题来说,这将是非常艰苦的工作。这还将为项目添加额外的复杂性。Ladislav是正确的:没有必要抽象到这个程度。

0
如果你担心可能要更换EF,那么你应该实现存储库模式和纯POCOS。
Codeplex上有一个很棒的项目,介绍了领域驱动设计,包括文档。你可以看一下。

http://microsoftnlayerapp.codeplex.com/


这对我来说似乎违背了持久性无知的目的。我的控制器层不应该关心我是使用ORM还是存储库模型。 - Nathan Ridley
如果这两个东西没有提供相同的功能,那么你的控制层肯定应该关心。自动跟踪和持久化更改的东西需要与不需要的基本不同的控制器逻辑。 - Tridus
你是正确的,正如我所说,你可以使用普通的POCOS并将它们作为DTO传递 - 它们应该是持久性无知的。仓储模式不会限制您使用任何特定的数据访问方法。 - William Xifaras

0
请在阅读了微软n层项目之后,阅读ayenede的博客。Ayende先生发布了一系列关于微软n层项目的优缺点的帖子。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接