【问题标题】:Entity Framework with layered architectures in Agile Development [closed]敏捷开发中具有分层架构的实体框架 [关闭]
【发布时间】:2013-12-06 05:24:37
【问题描述】:

我一直在使用 PHP ORM,有趣的一点是,由于是一种动态语言:在数据访问层中,我向 DB 发出请求,它返回一个“通用”对象(数组的好名字! ) 我在整个应用程序中将它用作我的实际 模型,直接在控制器和视图上!这让强类型场景感到惊讶!

现在在 C# 中,使用实体框架作为我的 ORM,它有自己的自动生成模型(实体),我在这里提出了一个问题:

Dal (with Entity Framework) and Model layers into MVC

结论是:在应用程序中使用这些 EF 的实体作为我的实际模型层是错误的,所以我需要获取这些数据层模型并转换为模型层中真正的应用程序模型......在我的控制器、视图中处理从数据库接收到的数据。

此外,我们还有一些非常棒的问题对我有所帮助:

  1. Entity Framework in Layered Architectures
  2. In MVC, does an ORM represent the model?
  3. Entity framework and Business Layer / logic

但我正在重新考虑在数据层中使用 EF,为什么? Entity Framework 中可爱的东西是 DbContext,基本上所有 ORM 都围绕它工作,如果我将这些 EF 的实体转换为我的模型层模型,我将浪费所有使事情变得更容易和更快的好东西,除了转置真正让我烦恼并使事情变得更难的类的辛勤工作!(请不要说 AutoMapper,我不能在我的工作中使用它,而且我不是在寻找第三方解决方案)。

为什么在模型层或单层中使用实体框架更快:

我会在模型层中拥有所有自动生成的模型,并且我 可以在我的整个应用程序中使用它们,我也会充分利用 使用 DbContext 的所有实体框架,快速简单。

但是,这让我感到害怕,因为我会直接在非数据层中访问数据,而 Controller 和 View 可以访问所有与数据相关的内容,而且我们都知道这种方法存在的问题。

所以我的问题是:

我假设 ORM 是为了让数据访问开发更容易、更快捷,就像我可以用 PHP 做的那样简单,而且效果很好。另外,我认为这对于敏捷开发来说是完美的,因为使用存储过程进行小型和快速的工作是一种痛苦(尽管我喜欢 SP)。所以这里是 Entity Framework 和 DbContext 让事情变得更容易和更快,对吧?但是,敏捷开发根本不会打成一片,所以这就是为什么在所有问题中我们都在谈论将 EF 放在数据层而不是模型层中。

但这会使使用 EF 的开发变得更慢和痛苦,我们浪费了它的优势,而且严重的是,在这种情况下使用存储过程会更快。 在分层架构中使用 EF 并没有真正快速的开发?

【问题讨论】:

  • automapper 之类的工具使从实体到视图模型的转换相对较快。我不接受你问题的前提。
  • 好吧,如果它对你有用,但你不知道我不能使用它的场景,我有权提出另一个解决方案的问题,好吗?你可以对我的问题做-1,但你很自私
  • @Maess AutoMapper 绝对不是解决所有架构问题的灵丹妙药。 AutoMapper 实际上会生成糟糕的自动生成的 ViewModel,其中包含许多您不想向控制器公开的实体属性。我希望我可以对您的评论投反对票。
  • 完全不正确,它只会映射模型中存在的属性。我不建议基于实体自动生成视图模型。
  • 在我们的项目中,我们使用 T4 代码生成和 DataObject.Net ORM(代码优先)。我们生成模型的扩展并用它完全生成视图模型。因为我们有可以将模型中的所有元数据获取到我们的模板中的类,所以我们可以生成任何东西。举个例子:我们还为 Kendo UI 视图生成 DataSources 和 DataModels。我们已经为我们的传统实现了第二个实现,它使用 LINQ to SQL。模型中的任何更改都会立即反映在所有层中,并且可以在任何视图上使用。我们的 ORM 就是模型。

标签: c# asp.net-mvc entity-framework orm


【解决方案1】:

我正在使用 Entity Framework Code-First 并且我的 POCO 需要符合 EntityFramework 的要求。我能想到影响设计的 3 个方面 - 可能还有更多

  1. 我的导航属性必须实现 ICollection<T> 并且必须有一个 setter - 所以我不能有一个没有 setter 的 ReadOnlyCollection<T> yet

  2. 如果我想延迟加载,那么我必须将我的导航属性标记为virtual。延迟加载意味着 Entity Framework 将生成继承自 Entities 的代理对象,有时这也会侵入,但如果您不想延迟加载,则不必延迟加载,POCO 将保持不受污染。

  3. 使用 Entity Framework,如果 POCO 有一个外键,生活会更轻松,但如果你愿意,你也可以make do with absent foreign keys

所以我的模型不是数据访问层的一部分,只是略有影响。而且他们不需要公开任何关于 Entity Framework 的内容。

我可以编写一个新类,添加或删除属性,更改关系,然后我可以搭建数据迁移以根据模型更改数据库。这意味着数据访问开发非常简单且非常快速

现在,您已经习惯在整个应用程序中使用模型,在 MVC 应用程序中使用 I'm sure many people do that。您的问题不在于实体框架,而在于 MVC。您应该提出问题 (as you have already) Why should I use view models? 并将其与您使用 PHP 的经验进行比较。

你为什么不使用ViewModels in your PHP controllers and Views?显然,一旦你这样做了,你就不会回去!

所以使用实体框架让您的数据访问速度更快。

然后使用 automapper 快速将模型映射到视图模型 - 或者不要自己在代码中映射它们 - 或者根本不使用 ViewModels 并继续像你目前在 PHP 中所做的那样

【讨论】:

  • EF 中的一个重要工具是实体更改跟踪:一旦我更改了某个值,EF 就会跟踪此更改并几乎不费吹灰之力地保存在数据库中,而且我很确定 EF 会消耗很多性能来完成这个成就。如果我使用 ViewModels,我将不再使用此更改跟踪,这不是很大的浪费吗?现在我必须搜索具有 id: X 的实体,手动更改一些属性并保存在数据库中。总结:要做更多的工作,减少性能,浪费工具.. 似乎 EF 只适用于实体,使用我自己的模型(视图模型)进行映射感觉不是一种自然的 EF 方式
  • @Wagner,ViewModel 的目的不是跟踪实体模型状态的未决更改,而是在网页和控制器操作之间移动数据(同样,它只是一个 DTO)。所以不,它没有被浪费,是的,当你准备好保存实体时,你必须查找它。 ViewModel 不负责为您自动化任何数据库内容。
  • @danludwig 我知道,这就是为什么我说使用 ViewModel 而不是 Entities 是一种浪费,因为我没有使用 EF 为我提供的更容易和更快的工具,这就是为什么我是说这样做感觉不自然。为什么 EF 为我提供了这个跟踪变化,而 DbContext 是 EF 的炉灶,我不会使用它?为什么要这样做?
  • @Wager 我在这里根本没有关注你,也许翻译中丢失了一些东西。您不使用 ViewModels 而不是实体。您可以同时使用它们,但目的不同:ViewModel 用于在网页和控制器操作之间移动数据,而实体用于在控制器操作(或较低层)和数据库之间移动数据。这就是 AutoMapper 发挥作用的地方,它在 ViewModel 和实体(或可能是某些命令/查询/其他服务 DTO 层)之间传输数据在控制器操作方法主体中
  • @danludwig 我更新了关于 AutoMapper 使用的问题。我不能使用 AutoMapper。我清楚地知道你在说什么 ViewModels,问题是在没有自动映射器的情况下维护 Entity ViewModel 的努力.. 以及丢失 EF 跟踪,因为一旦我更新我的 ViewModel 我必须手动更新数据库中的实体. EF 应该自动完成所有工作(并且它在单层应用程序中完成)时需要做很多工作。
【解决方案2】:

如果你只有一把锤子,那么一切都会像钉子一样。

不要将 EF 或任何 ORM 视为旨在使一切更轻松、更快捷的东西。它是工作的工具。 ORM 的作用是在物理关系模型 (SQL) 和概念对象模型 (CLR) 之间架起一座桥梁。它使在堆和表之间移动数据更容易、更快,仅此而已。

说出您对 AutoMapper 的看法,但同样,它是一种工作工具。数据传输对象的想法比 ORM 的想法还要久。事实上,这就是你的实体类——DTO。它们将应用程序的一层(概念对象模型)和另一层(物理关系模型)之间的关注点分开。 AutoMapper 所做的只是简化 DTO 代码。它不是“快速修复”,而是有目的的工具。

现在,如果您想一直使用实体 DTO 到应用程序的面向外部的表面,您可以这样做。这可能不是一个好主意,但没有什么能阻止你。但如果你这样做,那么我的问题是,你所说的“分层架构”中的层之间的分离在哪里?

回复评论:

我想您需要自己回答的问题是,哪个更重要:快速轻松地编写代码,或者拥有一个分层架构,可以在新需求迫使它增长时进行合理管理。毫无疑问,分层架构涉及更多的工作,除非您使用 T4 来生成像 @Paul Sinnema 这样的代码。与故事实现的最短距离通常是带有 SqlDataSource 的 ASP.NET WebForm。

如果您被允许使用 AutoMapper,它可以帮助您编写大量繁琐的代码。不要为此责怪 EF,责怪让你做 EF 加 MVC 减去 AutoMapper 的人。

【讨论】:

  • 我不能使用 AutoMapper,因为我不允许在某些项目中使用第三方产品。另外,我同意在我的整个应用程序中使用实体是非常错误的,但是在“正确”层中使用 EF 比使用存储过程要花费更多的时间。所以我猜我做错了什么,也许有更好更快的方法来完成这项工作。另外,关于 EF 的“大事”是跟踪我的实体的变化,如果我使用另一个类,这不会被跟踪,对吗?所以我在浪费 EF
【解决方案3】:

我倾向于将实体作为我的域模型,由应用程序中的服务执行。我为我的视图模型创建了完整的单独类,以维护两者之间的 SOC。

【讨论】:

  • 是的,我也是这样做的。但是就像我说的,在 PHP 中我不需要维护两个“环境”,这很困难并且消耗大量时间,而且 EF 的重要之处在于跟踪更改,如果我只是更改 ViewModel 它不会在数据库中更改。我正在为此寻找解决方案:让工作更轻松并利用所有 EF 优势。
  • 我认为尝试将两者结合起来是一条非常危险的道路。
【解决方案4】:

使用实体作为模型可能会产生意想不到的后果,包括数据丢失。考虑以下示例:

在 sprint 1 中,我创建了一个 widget 实体和一个用于创建和编辑新小部件的视图(我们称之为 View1)。 widget 具有以下属性:ID, prop1, prop2

在 sprint 2 中有一个故事要添加 prop3prop4 并创建一个新页面,您可以在其中编辑这些属性。假设与 sprint 1 不同的开发人员得到了这个故事。如果此开发人员没有将prop3prop4 属性添加到View1 作为隐藏字段,当有人使用View1 编辑widget 时,prop3prop4 属性将设置为空.

如果View1 和这个新视图有自己的视图模型,这些视图模型映射到widget 实体,则不会发生这种情况。

【讨论】:

  • 如果您先使用代码,则不会发生这种情况。这些更改将提交给源代码控制。我同意将 EF 与源代码控制一起使用是一团糟。 XML 的合并有它的缺点,这就是我们使用 DataObjects.Net 的原因,它使用纯 C# 类来描述模型。 C#代码的合并没问题。
  • 这将首先发生在代码上。由于两个视图都使用 Widget 作为模型,如果 View one 更新 Widget 并且 prop3 和 prop4 为 null,它们将被设置为 null,并且它们将为 null,因为它们是模型的一部分但不会出现在视图上(没有控件或隐藏字段)标准模型绑定器会将它们设置为空。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2010-10-29
相关资源
最近更新 更多