实体框架合并噩梦

Posted

技术标签:

【中文标题】实体框架合并噩梦【英文标题】:Entity Framework Merge Nightmare 【发布时间】:2010-11-28 21:43:53 【问题描述】:

我们采用了实体框架,我们发现当多人在各自的源代码控制分支中进行单独的更改时,当他们合并在一起时会出现大量冲突,从而导致模型文件损坏。

我们倾向于强制对文件进行独家签出,但我想避免这种情况。

我的问题是……

是否有更好的比较工具可以更好地处理这个问题,或者我们可以采取其他方法吗?

如果可能的话,寻找可以证明的东西。

新更新: 对于那些遇到这个问题的人,它基于旧的 EF。我建议转而使用 DbContext 而不是 EDMX。这里有很多关于它的信息。在我看来,数据库优先或代码优先的简单性远远超过了设计师的损失。

更新: 我们通过强制对文件进行独占更改来解决此问题。通过添加这个过程,我们完全消除了任何问题。虽然这不是理想的解决方案,但它是最可靠且最容易实施的。

【问题讨论】:

这与实体框架有什么关系?好像你有一个一般的源代码控制问题 - 但这与 ADO.NET EF 无关,我想说...... 我会说是的,EF 在这里有过错,因为每次进行最小的更改时都完全重新构建整个模型文件。 @mxmissile:好的,好点 - 这是我自己不喜欢 EF 的问题之一。自己研究使用其他方式(如代码生成)生成必要代码文件(例如每个实体一个文件)的其他方式。 我会说这一切都与 EF 有关。我有同样的问题,因此遇到了这个问题。 SVN 非常适合我们使用的所有其他东西(甚至大部分时间都是表单设计师),但在 EF 模型中却以惊人的方式失败。 【参考方案1】:

Craig Stuntz 很好地解释了造成这里大部分问题的是与设计器相关的 xml(实体和关联等在设计表面上的位置)。但是,edmx:Runtime 元素内的冲突解决是非常容易实现的。

处理与设计器相关的 xml 中的冲突的最佳策略是通过牺牲任何自定义布局并恢复为默认布局来完全绕过它们。

诀窍是删除<Diagrams> 元素的所有内容。设计器将毫无问题地打开并应用默认布局。

以下是将以默认布局打开的 EDMX 文件示例。请注意,<edmx:Runtime> 元素的内容也已删除,但这只是为了简洁起见 - 它不是解决方案的一部分。

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
  <!-- EF Runtime content -->
  <edmx:Runtime>
  <!-- Removed for brevity's sake only!-->
  </edmx:Runtime>
  <!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
  <Designer xmlns="http://schemas.microsoft.com/ado/2008/10/edmx">
    <Connection>
      <DesignerInfoPropertySet>
        <DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
      </DesignerInfoPropertySet>
    </Connection>
    <Options>
      <DesignerInfoPropertySet>
        <DesignerProperty Name="ValidateOnBuild" Value="true" />
        <DesignerProperty Name="EnablePluralization" Value="True" />
        <DesignerProperty Name="IncludeForeignKeysInModel" Value="True" />
      </DesignerInfoPropertySet>
    </Options>
    <!-- Diagram content (shape and connector positions) -->
    <Diagrams>
    </Diagrams>
  </Designer>
</edmx:Edmx>

请注意,此处应用的默认布局与您从设计器的上下文菜单中选择 Diagram | Layout Diagram 时的结果不匹配,这正是我所期望的。

更新:从Entity Framework 5 开始,这变得更容易了。在那里添加的multiple diagram support 将与图表相关的 xml 卸载到单独的文件中。请注意,我在 edmx 文件中仍然有一些与图表相关的旧标签,这些标签已经经历了多次实体框架升级。我只是从 edmx 文件中删除了名为 Diagrams(包括子项)的标签。

【讨论】:

这种方法的问题是每次有人编辑图表视图时都会重新填充&lt;diagrams&gt; 节点。对于较大的团队或承包商流动率高的团队,很难管理预防这种情况。我想知道您是否使用Git-Hooks 或类似方法成功确保每次提交代码时自动清除标签?这里的任何指针将不胜感激。 @Adam:请参阅上面的更新。从 Entity Framework 5 开始,这不再是一个问题。【参考方案2】:

有一些strategies for dealing with large Entity Framework models in this article。你可以考虑使用它们。但是,我发现 EDMX 的再生带来的大部分痛苦来自于在 GUI 设计器上通过拖放进行的更改。另一方面,从数据库或通过属性窗口进行更新模型往往会以相当明智的方式进行更改,并且不会很难合并。

据我所知,最大的问题是概念/映射/存储模型中的可视对象模型的布局信息在同一个文件中。换句话说,问题不在于文件本身的大小或对实体模型本身所做的更改,而是当您在 GUI 设计器上拖放对象时发生的大规模重新排列。我希望 GUI 设计器布局和概念/映射/存储模型放入不同的文件中。我相信这将消除合并模型更改的大部分痛苦。

因此,我们有一个半官方的政策,即不更改模型的图形布局。这并没有太大的损失,因为当您的模型中有超过几十个实体时,仅一页的 GUI 设计器无论如何都不是真正有用的。而且它确实让合并变得更加容易。

实体框架的第 4 版将有一个基于 T4 模板生成工件的选项。我不是专家,但可以使用 T4 模板将 GUI 布局信息引入不同的文件。

【讨论】:

哇,我不敢相信这是 EF 团队对可扩展性的回应。哇。感谢您的链接 (+1)! Michael,那篇文章是为 v1.1 写的。 v4 功能仍在开发中。【参考方案3】:

如您所说,一种选择是锁定文件。

另一种可能的选择是通过团队中的一个人发送所有模型更改。

另一种选择是将文件分成更小的文件(例如每个类一个),可能会在此过程中留下一些设计师支持。

另一种选择是创建您自己的流程,可能会使用 XSLT 来转换 EDMX 文件,但我不确定这会是什么样子,designer.cs 文件是一个很难合并的文件。

另一种选择是考虑不同的 ORM。

我不确定他们是否会在 EF 的下一版本中改进这一点。在单个文件中投入这么多数据并不意味着任何类型的可扩展性(但 LinqToSql 做同样的事情 - 在这种情况下,Damien Guard 创建了一些 T4 模板来拆分文件,不确定 EF 是否存在类似的东西)。

【讨论】:

也许只是一种不同的方法来为 EF 生成代码类(而不是一起扔掉 EF)。我知道 CodeSmith Tools 正在开发 PLINQO (plinqo.com) 代码生成模板的 EF 版本... 不幸的是,像 CodeSmith 这样的商业工具并不总是一种选择,但是是的,有一些商业工具可以帮助解决这个问题。其中一些工具可能会保持与 EF 设计器的兼容性,而其他工具可能不会。 虽然团队规模/可用资源始终是一个因素,但我同意只分配一个人来更改实体模型的方式。即使您不使用实体框架,也不应该存在与数据库架构或围绕它的对象相关的任何内容。【参考方案4】:

出于这个原因,我实际上试图说服我的公司使用 Code First,但不幸的是,我被关闭了。他们喜欢能够使用设计师。不幸的是,我在上次生产部署中遇到了问题,其中我们的一个 WCF 服务中有大约 10 个端点来支持多个消费者,并且在合并过程中,EDMX 文件的 CS 部分中有几个重复的条目.

在我的个人项目中,我只使用 Code First。对我来说,这与我更喜欢手动变速箱而不是自动变速箱的原因相同。当然,模型设计者可能更容易(有时,正如我们所讨论的那样),但使用 Code First,您可以更直接地控制正在发生的事情。就像手动变速箱一样。 :)

【讨论】:

【参考方案5】:

我对 EF 并不是特别熟悉,但我在自动生成的代码过于冗长和脆弱方面遇到了很多问题。在每种情况下,如何合并它的最佳答案是“不要”。在您的场景中,这可能意味着以下两件事之一:

1) 收紧你的代码提升模型,让 EF 代码只向一个方向流动。换句话说,每个冲突都将被解决为“从源分支复制”(AcceptTheirs)或“保持目标不变”(AcceptYours),每个人都应该提前知道哪个是哪个。最常见的是,在将新测试的代码推向分支树的稳定节点时,您需要 AcceptTheirs,在将修复合并回不稳定/开发分支时,您需要 AcceptYours。 (如果有 >1 个开发分支,那么您需要对事物进行分区,以便只有在给定分支中工作的团队拥有的 EF 代码遵循后一条规则。他们不是有意更改的任何内容都应该被其他团队的代码覆盖从集成分支流出,如有必要,使用 AcceptTheirs。)

/- [...] /- v1.1 /- 发布 + 整合 - 开发1 - 开发2 - [...]

“Merge down, copy up”

2) 从字面上看,不要合并它们;从流程中完全排除 EF 代码。当集成分支需要更改数据库和/或 ORM 时,直接从数据库重新生成代理类。 (当然,在解决 + 构建对 SQL 文件的任何冲突更改之后)Extreme 版本:在每次自动构建期间执行此操作,而不仅仅是在合并时。

【讨论】:

以上是关于实体框架合并噩梦的主要内容,如果未能解决你的问题,请参考以下文章

在实体框架核心中合并迁移

ODAC 12c 和实体框架 6

如何在 MCV 中合并两个实体框架查询

当我不知道记录是不是存在时,如何使用实体框架进行合并?

实体框架代码优先 - 将两个字段合并为一个集合

实体框架和模拟