代码优先与模型/数据库优先[关闭]

Posted

技术标签:

【中文标题】代码优先与模型/数据库优先[关闭]【英文标题】:Code-first vs Model/Database-first [closed] 【发布时间】:2011-07-23 17:03:39 【问题描述】:

使用 Entity Framework 4.1 Code-first 优于 Model/Database-first 和 EDMX 图的优缺点是什么?

我正在尝试完全了解使用 EF 4.1 构建数据访问层的所有方法。我正在使用存储库模式和IoC

我知道我可以使用代码优先的方法:手动定义我的实体和上下文,并使用ModelBuilder 来微调架构。

我还可以创建EDMX 图表并选择使用 T4 模板生成相同的POCO 类的代码生成步骤。

在这两种情况下,我都会得到与 ORM 无关的 POCO 对象和派生自 DbContext 的上下文。

Database-first 似乎最吸引人,因为我可以在 Enterprise Manager 中设计数据库,快速同步模型并使用设计器对其进行微调。

那么这两种方法有什么区别呢?仅仅是 VS2010 与 Enterprise Manager 的偏好吗?

【问题讨论】:

Entity Framework 7 正在删除 EDMX:msdn.microsoft.com/en-us/magazine/dn890367.aspx @CADbloke Entity Framework 7 现在是 Entity Framework Core 1.0 对于任何其他浏览器,除非您对 7000 个长 XML 文件有耐心并解决上述合并冲突,go code first 让自己头疼 在 2015 年 1 月,roland.kierkels.net/c-asp-net/… 有一篇很好的关于这三种方法的文章 几乎所有给出的答案都是“我认为”...“主要基于意见”的绝对定义。 【参考方案1】:

我认为区别在于:

代码优先

非常受欢迎,因为铁杆程序员不喜欢任何类型的设计师,而且在 EDMX xml 中定义映射过于复杂。 完全控制代码(没有难以修改的自动生成代码)。 一般的期望是您不必为 DB 烦恼。 DB只是一个没有逻辑的存储。 EF 将处理创建,您不想知道它是如何完成这项工作的。 对数据库的手动更改很可能会丢失,因为您的代码定义了数据库。

数据库优先

如果您拥有由 DBA 设计的、单独开发的数据库或者如果您有现有的数据库,则非常受欢迎。 您将让 EF 为您创建实体,并在修改映射后生成 POCO 实体。 如果您想要 POCO 实体中的其他功能,您必须修改 T4 模板或使用部分类。 可以手动更改数据库,因为数据库定义了您的域模型。您可以随时从数据库中更新模型(此功能效果很好)。 我经常将它与 VS 数据库项目(仅限高级版和旗舰版)一起使用。

模型优先

恕我直言,如果您是设计师粉丝(= 您不喜欢编写代码或 SQL),恕我直言。 您将“绘制”您的模型并让工作流生成您的数据库脚本和 T4 模板生成您的 POCO 实体。您将失去对实体和数据库的部分控制权,但对于简单的小型项目,您将非常高效。 如果您想要 POCO 实体中的其他功能,您必须修改 T4 模板或使用部分类。 对数据库的手动更改很可能会丢失,因为您的模型定义了数据库。如果您安装了数据库生成电源组,这会更好。它将允许您更新数据库架构(而不是重新创建)或更新 VS 中的数据库项目。

我希望在 EF 4.1 的情况下,还有其他几个与 Code First 与 Model/Database first 相关的功能。 Code first 中使用的 Fluent API 不提供 EDMX 的所有功能。我希望存储过程映射、查询视图、定义视图等功能在首先使用模型/数据库和DbContext(我还没有尝试过)时有效,但它们在代码优先时没有。

【讨论】:

@Ladislav - 感谢您的全面回答。澄清一下:除了 fluent API 的一些限制之外,这些方法之间没有真正的技术差异吗?更多的是关于开发/部署过程/方法?例如,我对 Dev/Test/Beta/Prod 有单独的环境,我将在 Beta/Prod 上手动升级数据库,因为对架构的更改可能需要一些复杂的数据修改。对于开发/测试,我很高兴 EF 删除和创建数据库,因为我将自己在初始化程序中使用测试数据播种它们。 我设计数据库已经很长时间了,我似乎无法想象除了数据库先做任何事情。其实我还是写了很多存储过程来做更大容量的select语句之类的,然后我会以性能的名义做一个函数导入到EF模型中。 高容量选择语句是什么意思?存储过程并不比从应用程序发送的 SELECT 快。 可以在您的应用程序中使用 SQL。该 SQL 很可能会嵌入到已编译的代码中,并且任何更改都需要重新编译和重新部署,而存储过程的更改只需要编辑存储过程。在这种情况下,客户/客户/用户将受到变化的影响较小。 @JakubKonecki,无论您在 DbContext 中找不到的 ObjectContext 中的什么,只需使用 ((IObjectContextAdapter)dbcontext).ObjectContext【参考方案2】:

我认为“Programming Entity Framework”的作者 Julie Lerman 的这个简单的“决策树”应该有助于更有信心地做出决策:

更多信息Here。

【讨论】:

这不完整。如果您不想使用可视化设计器但您确实有一个现有的数据库怎么办? 更糟糕的是......现实生活中的决策不是由图表完成的,而是由您在使用代码优先时面临的技术限制完成的,例如您不能在字段上创建唯一索引,也不能删除树表中的分层数据,为此您需要使用 context.Table.SqlQuery("select...") 的 CTE。模型/数据库首先没有这些缺点。 @davenewza 那不是第一条路吗? @davenewza 现有数据库 => 现有类?代码优先:数据库优先:) @davenewza 使用实体框架 Powertools 从 DB 创建您的 POCO 类。 Code First to an Existing Database【参考方案3】:

数据库优先和模型优先没有真正的区别。 生成的代码是相同的,您可以结合这些方法。例如,您可以使用设计器创建数据库,而不是使用 sql 脚本更改数据库并更新模型。

当您首先使用代码时,如果没有重新创建数据库并丢失所有数据,您将无法更改模型。恕我直言,这个限制非常严格,不允许在生产中首先使用代码。目前它还不能真正使用。

代码优先的第二个小缺点是模型构建器需要主数据库的权限。如果您使用 SQL Server Compact 数据库或控制数据库服务器,这不会影响您。

代码优先的优点是代码非常简洁。您可以完全控制此代码,并且可以轻松修改并将其用作您的视图模型。

当您创建没有版本控制的简单独立应用程序并在需要在生产中修改的项目中首先使用模型\数据库时,我建议您使用代码优先方法。

【讨论】:

如果您打算使用 SQL 脚本手动更新生产环境,您仍然可以使用 Code First 执行相同的操作。您只需根据需要生成更改脚本。有几个工具可以自动化这些增量,您可以继续使用 Code First。您只需将 Code First 初始化程序更改为 CreateDatabaseIfNotExists 之类的东西,以免删除当前数据库。 一些区别是导入视图然后重新生成数据库,其中视图变成表。很难生成新数据库并与产品数据库进行比较以查看是否同步。 Model First 不支持用户定义的 SQL 函数(至少在 EF4 中,不知道这是否改变了)。使用 Database First,您可以导入 UDF 并在 LINQ 查询中使用它们。 没有区别?尝试导入视图和 SimpleMembership 表,然后从模型生成数据库,看看你得到了什么。差远了!这些应该是往返的,但随后 MSFT 基本上放弃了 MF 和 DF 来代替 CF,这在使用视图和存储过程方面也是不完整的。 "当您首先使用代码时,如果没有重新创建数据库并丢失所有数据,您将无法更改模型。" - 我创建了一个非常简单的 EF 代码优先项目,创建了一个迁移以将列添加到现有表,并使用 update-database 应用迁移。我的表中仍然存在所有现有数据,所以这个说法似乎不正确?【参考方案4】:

引用http://www.itworld.com/development/405005/3-reasons-use-code-first-design-entity-framework 的相关部分

在实体框架中使用代码优先设计的三个理由

1) 不那么笨拙,不那么臃肿

使用现有数据库生成 .edmx 模型文件和 相关的代码模型会产生大量自动生成的代码。 恳求您永远不要触摸这些生成的文件,以免破坏 某些东西,或者您的更改会被下一代覆盖。这 在这个混乱中,上下文和初始化程序也被卡在一起了。什么时候 您需要为生成的模型添加功能,例如 计算只读属性,需要扩展模型类。 这最终成为几乎每个模型的要求,你最终 为所有内容提供扩展名。

在代码优先的情况下,您的手工编码模型成为您的数据库。最正确 您正在构建的文件会生成数据库设计。 没有额外的文件,也不需要创建类 当您想要添加属性或其他任何内容时扩展 数据库不需要知道。您可以将它们添加到 只要您遵循正确的语法,就可以使用相同的类。哎呀,你甚至可以 如果需要,可以生成一个 Model.edmx 文件来可视化您的代码。

2) 更好的控制

当您首先使用 DB 时,您将受制于生成的内容 在您的应用程序中使用的模型。偶尔取名 约定是不可取的。有时关系和 关联并不是您想要的。其他时间非瞬态 与延迟加载的关系会对您的 API 响应造成严重破坏。

虽然模型生成问题几乎总有解决方案 你可能会遇到,先去代码会给你完整的和好的 从一开始就进行粒度控制。您可以控制两者的各个方面 您的代码模型和您的数据库设计从您的舒适 业务对象。您可以精确地指定关系、约束、 和协会。您可以同时设置属性字符限制 和数据库列大小。您可以指定哪些相关的集合 将被急切加载,或者根本不被序列化。简而言之,你是 负责更多的事情,但你可以完全控制你的应用程序 设计。

3)数据库版本控制

这是一件大事。版本控制数据库很难,但代码优先 和代码优先迁移,它更有效。因为你的 数据库模式完全基于您的代码模型,按版本 控制您的源代码,您正在帮助对数据库进行版本控制。 你负责控制你的上下文初始化 可以帮助您做诸如种子固定业务数据之类的事情。你也是 负责创建代码优先迁移。

当您第一次启用迁移时,配置类和初始 产生迁移。初始迁移是您当前的架构 或您的基线 v1.0。从那时起,您将添加迁移 带有时间戳并标有描述符以帮助 版本的排序。当您从包中调用 add-migration manager,将生成一个新的迁移文件,其中包含所有内容 在 UP() 和 DOWN() 函数。 UP 函数将更改应用于数据库, DOWN 功能会删除您想要的事件中的相同更改 回滚。更重要的是,您可以编辑这些迁移文件以添加 其他更改,例如新视图、索引、存储过程和 不管怎么说。它们将成为您真正的版本控制系统 数据库架构。

【讨论】:

【参考方案5】:

代码优先似乎是后起之秀。我快速浏览了 Ruby on Rails,它们的标准是代码优先,带有数据库迁移。

如果你正在构建一个 MVC3 应用程序,我相信 Code first 有以下优点:

简单的属性修饰 - 你可以用validation、require等属性修饰字段,EF建模很尴尬 没有奇怪的建模错误 - EF 建模经常会出现奇怪的错误,例如当您尝试重命名关联属性时,它需要匹配底层元数据 - 非常不灵活。 合并并不尴尬 - 使用 mercurial 等代码版本控制工具时,合并 .edmx 文件很痛苦。你是一个习惯于 C# 的程序员,你正在合并一个 .edmx。代码优先并非如此。 首先对比 Code,您可以完全控制,无需处理所有隐藏的复杂性和未知因素。 我建议您使用 Package Manager 命令行工具,甚至不要使用图形工具将新控制器添加到脚手架视图。 DB-Migrations - 然后您还可以启用-迁移。这太强大了。您在代码中对模型进行更改,然后框架可以跟踪架构更改,因此您可以无缝部署升级,架构版本会自动升级(并在需要时降级)。 (不确定,但这可能也适用于模型优先)

更新

该问题还要求将代码优先与 EDMX 模型/数据库优先进行比较。代码优先也可用于这两种方法:

模型优先:首先编码 POCO(概念模型)然后生成数据库(迁移);或 数据库优先:在给定现有数据库的情况下,手动对 POCO 进行编码以进行匹配。 (这里的区别在于 POCO 不会自动生成给现有的数据库)。您可以使用Generate POCO classes and the mapping for an existing database using Entity Framework 或Entity Framework 5 - How to generate POCO classes from existing database 接近自动。

【讨论】:

Model-first 不是先编码 POCO,这是 Code First,Model-First 是一个可视化设计器,用于自动生成 POCO,然后从模型生成数据库。 如今在视觉和代码路线中,您可以先做“模型”,也可以先做“数据库”。第一个是手动设计(通过代码或可视化编辑器),第二个是构建数据库并创建模型(POCO 或 EDMX)。【参考方案6】:

我首先使用 EF 数据库,以便提供更大的灵活性和对数据库配置的控制。

EF 代码优先和模型优先起初看起来很酷,并且提供数据库独立性,但是这样做不允许您指定我认为非常基本和常见的数据库配置信息。例如表索引、安全元数据或具有包含多个列的主键。我发现我想使用这些和其他常见的数据库功能,因此无论如何都必须直接进行一些数据库配置。

我发现在 DB first 期间生成的默认 POCO 类非常干净,但是缺少非常有用的数据注释属性或到存储过程的映射。我使用 T4 模板来克服其中的一些限制。 T4 模板很棒,尤其是与您自己的元数据和部分类结合使用时。

Model first 似乎有很大的潜力,但在复杂的数据库模式重构期间给了我很多错误。不知道为什么。

【讨论】:

可以先使用代码定义复合键 - ***.com/questions/5466374/… 对于以后的读者来说,不再是这种情况了,可以在EF Code First中添加索引、多列主键之类的东西。 EF 应该已经修复,以便所有 3 种方法可以在同一个数据库上互换使用,因为所有 3 种方法都有优点和缺点 另外,不是理想的代码优先解决方案的真相我首先使用数据库是因为将来迁移到其他 IDE/语言,我希望拥有稳固和集成的数据库结构,另一个事实我更喜欢数据库首先是更改数据存储任何部分的灵活性。【参考方案7】:

在SP1之前处理大型模型非常慢,(在SP1之后没有尝试过,但据说现在很容易)。

我仍然首先设计我的表,然后内部构建的工具为我生成 POCO,因此它承担了为每个 poco 对象执行重复任务的负担。

当您使用源代码控制系统时,您可以轻松地跟踪您的 POCO 的历史,而使用设计器生成的代码并不是那么容易。

我的 POCO 有一个基础,这让很多事情变得非常容易。

我的所有表都有视图,每个基本视图都为我的外键带来基本信息,并且我的视图 POCO 派生自我的 POCO 类,这再次非常有用。

最后我不喜欢设计师。

【讨论】:

'当您使用源代码控制系统时,您可以轻松地跟踪您的 POCO 的历史,使用设计器生成的代码并不容易。' - 我将设计器生成的代码保存在源代码管理中,因此我可以随时查看历史记录。 @JakubKonecki 您是否曾尝试在 3 人以上的团队中合并 EDMX 文件?这只是一种痛苦......相反,人们试图避免合并,只是采用另一个修订版并重复他们自己的更改,因为在具有数千行 XML 的自动生成文件中合并很容易失败。【参考方案8】:

数据库优先方法示例:

无需编写任何代码: ASP.NET MVC / MVC3 Database First Approach / Database first

而且我认为它比其他方法更好,因为这种方法的数据丢失更少。

【讨论】:

您能否详细说明使用 DB 优先方法会“减少数据丢失”?如果要将现有表一分为二,您将如何执行数据转换? 您可能最终会编写一个负责转换的 sql 脚本。一般来说,MS 宣布用他们的新版本改进 Code First 数据迁移,所以这可能不会成为未来的争论。 数据库首先的问题是数据库设计通常具有错误的抽象,这些抽象会泄漏到您的模型中...连接表等。数据库的工作只是持久化您的模型。 这个“答案”是一个基于观点的观点,对你的论点没有任何意义,一句话不代表立场。 您能否详细说明使用 DB 优先方法会“减少数据丢失”?【参考方案9】:

恕我直言,我认为所有模型都有一个很好的位置,但我对模型优先方法的问题是在许多大型企业中,DBA 控制数据库,如果不使用数据库优先方法,您将无法获得构建应用程序的灵活性。我参与过许多项目,在部署时他们想要完全控制。

尽管我同意 Code First、Model First、Database first 的所有可能变化,但您必须考虑实际的生产环境。因此,如果您的系统将是一个拥有许多用户的大型用户群应用程序,并且 DBA 正在运行该节目,那么您可能会考虑将数据库作为我的首选选项。

【讨论】:

你是对的。 MS 为程序员提供了不同的方法,因为它们是不同的场景。您应该了解所有情况并根据您的情况决定什么最适合项目,然后您最喜欢什么。【参考方案10】:

我认为代码优先的优点之一是您可以备份您对 Git 等版本控制系统所做的所有更改。因为您所有的表和关系都存储在本质上只是类的东西中,所以您可以回到过去,看看您的数据库之前的结构是什么。

【讨论】:

这点很好 Visual Studio 允许创建数据库项目。有了这样的项目,您就拥有完整的架构版本控制,可以比较数据库架构和数据并生成更改脚本,将架构或数据更改应用于数据库。见visualstudio.microsoft.com/vs/features/ssdt @Cogitator 我知道此功能可用于 MSSQL 支持的数据库。您知道 mysql 支持的数据库的此类项目/模板吗?

以上是关于代码优先与模型/数据库优先[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

csharp EF代码优先修改生成的数据库与模型一样

如何禁用代码优先迁移

(转)EF中数据优先,模型优先和代码优先

将实体框架从数据库优先转换为代码优先

PHP中的代码优先实体框架模型

EF 增删改