【问题标题】:Combine Code First & Database First In Single Model?在单一模型中结合代码优先和数据库优先?
【发布时间】:2016-11-09 17:41:13
【问题描述】:

有没有办法在同一上下文中结合代码优先和数据库优先?在编辑 EDMX 文件时,我们遇到了大量的开发时性能问题(保存需要 1.5 分钟)。我已经将我们的非插入/更新/删除 UDF/存储过程移到了一些自动生成模型优先代码的自定义 T4 模板中,但是当涉及 EDMX 时,我似乎无法调用 OnModelCreating

我们考虑过的其他事情,但由于某种原因不起作用:

  1. 我们不能(合理地)将我们的代码分离到多个上下文中,因为我们的实体关系中有很多重叠。似乎也有不少走这条路的人后悔了。

  2. 我们尝试了 2 种不同的上下文,但实体和 UDF 之间存在相当多的连接。这可能是我们最后的希望,但我真的很想避免它。

  3. 我们无法切换到 Dapper,因为很遗憾我们大量使用了 IQueryable

  4. 我们尝试完全采用 Code-First,但我们在 EDMX 中使用的某些功能不受支持(主要与插入/更新/删除存储过程映射相关)。

【问题讨论】:

  • EDMX 文件不会为上下文创建分部类吗?好久没用了……
  • 确实如此,但据我所知,如果您使用的是 EDMX,则不会调用 OnModelCreating。
  • 我不认为是这种情况?
  • 默认模板在 OnModelCreating 中有这个: throw new UnintentionalCodeFirstException();所以我认为它不会被调用。

标签: entity-framework entity-framework-6


【解决方案1】:

看看下面的链接。我以类似的方式回答了另一个问题:
How to use Repository pattern using Database first approach in entity framework

正如我在那篇文章中提到的,我个人会尝试切换到 Code First 方法并摆脱 EDMX 文件,因为它已被弃用,最重要的是,与 Code 相比,维护工作相当可观且复杂得多第一种方法。

从 Model First 方法切换到 Code First 并不难。下面是一些步骤和图片:

  1. 在项目级别显示所有文件并展开 EDMX 文件。您会注意到 EDMX 文件有一个 .TT 文件,该文件将嵌套多个文件,模型上下文和 POCO 在它们之间分类为 .cs 或 .vb 类(取决于您使用的语言)。见下图:
  2. 卸载项目,右键单击然后编辑。
  3. 看下图,注意上下文和TT文件的依赖关系
  4. 移除依赖,xml元素应该如下图所示:
  5. 对模型类(具有模型定义的类)重复该过程
  6. 重新加载您的项目,删除 EDMX 文件
  7. 您可能需要执行一些 tweeks 并更新名称/引用。

我过去做过几次,它在生产中完美无缺。您还可以寻找为您执行此转换的工具。

这可能也是您重新思考架构的好机会。

顺便说一句:要点 4 不应该成为你的阻碍。您可以通过 EF 映射/使用存储过程。请看以下链接:
How to call Stored Procedure in Entity Framework 6 (Code-First)?

【讨论】:

  • 您可能还想查看存储库模式和 CQRS 模式。它们都有不同的好处,可能有助于满足您的需求。
【解决方案2】:

似乎也有不少走这条路的人[多语境]后悔了。

我不是其中之一。

您的核心问题是上下文太大。所以分手吧。我知道不可避免地会有一些实体应该在多个上下文之间共享,这可能会导致类名重复。解决此问题的一种简单方法是将类重命名为特定于上下文的名称。

例如,我有一个ApplicationUser 表(谁没有)映射到主上下文中具有相同名称的类,但映射到我的AuthorizationContextReportingUser 中的类AuthorizationUserReportingContext。这根本不是问题。无论如何,大多数用例都围绕一种上下文类型,因此不可能混淆。

我什至有专门的上下文,可以处理与其他上下文相同的数据,但以更经济的方式。例如,上下文不映射到数据库中的计算列,因此在插入和更新之后没有读取(除了标识值)。

所以我建议你去,因为...

有没有办法在同一上下文中结合代码优先和数据库优先?

不,没有。两种方法都有不同的方式来构建DbModel(包含存储模型、类模型以及两者之间的映射)。在生成的DbContext 中,您甚至会看到抛出了UnintentionalCodeFirstException,以开车回家,您不应该使用该方法。

主要与插入/更新/删除存储过程映射有关

正如在另一个答案中所说,将 CUD 操作映射到存储过程是 supported in EF6 code-first

【讨论】:

    【解决方案3】:

    我是从你对另一个question 的评论中的链接来到这里的,你问的是:

    您提到代码优先和数据库优先是“技术上可行的”,您能解释一下如何实现吗?

    首先,另一个问题的背景完全不同。那里的 OP 询问是否可以在同一个项目中同时使用数据库优先和代码优先方法,但重要的是,不一定是相同的上下文。我所说的“技术上可能”适用于前者,而不是后者。绝对没有办法在同一上下文中同时使用代码优先和数据库优先。实际上,更具体一点,假设无法利用现有数据库并使用新实体迁移相同的数据库。

    由于微软在开发 EF 时的一些不幸的命名,这里的术语有点混乱。最初,您只有模型优先和数据库优先。两者都使用了 EDMX。唯一的区别是模型优先允许您设计实体并从中创建数据库,而数据库优先则使用现有数据库并从中创建实体。

    在 EF 4.1 中引入了代码优先,它完全抛弃了 EDMX,让您可以使用 POCO(普通的旧类对象)。但是,尽管名称如此,Code-first 可以并且始终能够使用现有数据库或创建新数据库。代码优先,然后是真正的模型优先和数据库优先,结合起来,减去可怕的 EDMX。最近,EF 团队终于更进一步,完全弃用了 EDMX,包括模型优先和数据库优先的方法。 建议此时继续使用其中任何一个,并且您可以预期在未来版本的 Visual Studio 中将完全放弃对 EDMX 的支持。

    说了这么多,让我们来看看事实吧。您不能在单个上下文中同时拥有现有数据库和 EF 管理的数据库。您至少需要两个:一个用于现有表,另一个用于由 EF 管理的表。更重要的是,这两个上下文必须引用不同的数据库。如果 EF 管理的数据库中有任何现有表,EF 将尝试删除它们。总而言之,您必须将 EF 管理的内容与外部管理的内容隔离开来,这意味着您无法在一个上下文和另一个上下文中的实体之间创建外键。

    您在这里唯一真正的选择是只做“数据库优先”的所有事情。换句话说,您只需将数据库视为现有数据库并手动创建新表、更改列等,而完全不依赖 EF 迁移。在这方面,您还应该继续转储 EDMX。将所有实体生成为 POCO,并在您的上下文中简单地禁用数据库初始化程序。换句话说,代码优先与现有数据库。我有additional information,如果你需要的话。

    【讨论】:

      【解决方案4】:

      感谢大家的深思熟虑和彻底的答案。

      许多其他答案都假定 EF Code-First 中的存储过程映射工作相同,但事实并非如此。我对此有点模糊,因为我查看它已经有大约 6 个月了,但我相信从 EF 6.3 开始,代码首先存储过程要求您将每一列从您的实体传递到您的插入/更新存储过程,并且您仅将键列传递给您的删除过程。没有选项可以选择可以传递的列。我们需要维护谁删除了一条记录,因此我们必须传递一些额外的信息,而不仅仅是一个简单的密钥。

      话虽如此,我最终做的是使用 T4 模板从数据库中自动生成我的 EDMX/Context/Model 文件(以及一些额外的元数据)。这将我们的开发者体验时间从 1.5 分钟缩短到了大约 5 秒。

      我希望 EF 存储过程映射将得到改进,以实现对 EDMX 的模仿,然后我可以只代码生成 Code-First 映射并完全删除 EDMX 生成。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 2013-03-13
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多