结合Code First&单一模型中的数据库优先?

时间:2016-11-09 17:41:14

标签: entity-framework entity-framework-6

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

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

  1. 我们不能(合理地)将我们的代码分离到多个上下文,因为我们的实体关系存在很多重叠。看起来很像走这条路的人都后悔了。

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

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

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

    < / LI>

4 个答案:

答案 0 :(得分:4)

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

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

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

  1. 显示项目级别的所有文件并展开EDMX文件。您会注意到EDMX文件有一个.TT文件,该文件将嵌套多个文件,模型上下文和POCO之间将它们分为.cs或.vb类(取决于您使用的语言)。见下图:
    enter image description here
  2. 卸载项目,右键单击,然后进行编辑。
  3. 请参阅下图,注意上下文与TT文件之间的依赖关系 enter image description here
  4. 删除依赖项,xml元素应如下图所示:
    enter image description here
  5. 对Model类(具有模型定义的类)
  6. 重复此过程
  7. 重新加载项目,删除EDMX文件
  8. 您可能需要做一些tweek并更新名称/参考。
  9. 我过去曾做过几次这样做,它在制作上完美无瑕。您还可以查找为您执行此转换的工具。

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

    BTW:子弹点4不应该成为你的噱头。您可以通过EF映射/使用存储过程。请看以下链接:
    How to call Stored Procedure in Entity Framework 6 (Code-First)?

答案 1 :(得分:2)

  

似乎很多人已经走了这条路[多重背景]后悔。

我不是其中之一。

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

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

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

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

  

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

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

  

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

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

答案 2 :(得分:1)

我从你评论中的一个链接中找到了另一个question,你在那里问:

  

你提到代码优先&amp;数据库优先是技术上的可能&#34;你能解释一下如何实现这个目标吗?

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

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

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

尽管如此,让我们回顾一下事实。您不能在单个上下文中同时拥有现有数据库和EF托管数据库。您至少需要两个:一个用于现有表,一个用于由EF管理的表。更重要的是,这两个上下文必须引用不同的数据库。如果EF管理的数据库中存在任何现有表,则EF将尝试删除它们。无论长短,您都必须将EF管理的东西与外部管理的东西隔离开来,这意味着您无法在一个上下文中的实体之间创建外键。

这里唯一真正的选择是做所有事情&#34;数据库优先&#34;。换句话说,您必须将数据库视为现有数据库并手动创建新表,更改列等,而不依赖于EF迁移。在这方面,您还应该继续转储EDMX。将所有实体生成为POCO,并在上下文中禁用数据库初始化程序。换句话说,Code-first与现有数据库。如果您需要,我有additional information

答案 3 :(得分:0)

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

许多其他答案都假设EF Code-First中的存储过程映射的工作方式相同,但它们没有。我对它有点模糊,因为我看了它已经有6个月了,但我相信从EF 6.3开始,第一个存储过程要求你将实体中的每一列都传递到插入/更新存储过程,并且您只将密钥列传递给删除过程。没有选项可以选择您可以传递的列。我们需要维护谁删除了一条记录,所以除了一个简单的密钥外,我们还要传递一些额外的信息。

话虽这么说,我最终做的是使用T4模板从数据库自动生成我的EDMX / Context / Model文件(带有一些额外的元数据)。这使我们的开发人员时间从1.5分钟缩短到大约5秒钟。

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