在本节中,我们将使用实体框架代码先行迁移功能对模型类进行修改,并使修改应用带数据库中。
默认情况下,当我们使用实体框架代码先行自动创建一个数据库,像我们在本系列前面做的那样,代码首先添加一张表到数据库中,以帮助跟踪数据库架构是否是同步的模型类是产生的。如果它们不同步,实体框架抛出一个错误。这使得它更容易在早期开发时跟踪发现问题,否则,我们可能在运行时发现隐晦错误。
为模型修改建立代码先行迁移
我们使用的是Visual Studio 2012,在“解决方案资源管理器”中双击我们的数据库文件,打开数据库工具。Visual Studio Express for Web将显示“数据库资源管理器”,Visual Studio 2012 将显示“服务器资源管理器”。
在数据库工具中,在MovieDbContext上右键点击并选择删除。(删除的是数据库链接)
回到解决方案资源管理器。在Movies.mdf file文件上右键单击并选择删除。(真正删除数据库文件)
生成应用程序,确认没有编译错误。
在VS2012工具菜单里,点击“库程序包管理器”=》程序包管理器控制台
在控制台的“PM>”标记后,输入“Enable-Migrations -ContextTypeName Mvc_Movie.Models.MovieDBContext”(注:如果解决方案的名字Mvc和Movie中间有一空格在这里用_代替)
Enter后输出如下信息:
PM> Enable-Migrations -ContextTypeName Mvc_Movie.Models.MovieDBContext Checking if the context targets an existing database... Code First Migrations enabled for project Mvc Movie. PM>
上面的Enable-Migrations 命令创建了一个新的migrations文件夹,并在该目录下创建了Configuration.cs文件。
使用Visual Studio打开Configuration.cs文件。使用以下代码替换Seed方法内容:
protected override void Seed(Mvc_Movie.Models.MovieDBContext context) { context.Movies.AddOrUpdate( p => p.Name, new Movie { Name = "少年派的奇幻漂流之旅", Date = DateTime.Now }, new Movie { Name = "一九四二", Date = DateTime.Now }, new Movie { Name = "王的盛宴", Date = DateTime.Now } ); }
以上代码需要类中导入名称空间using Mvc_Movie.Models;
代码先行迁移机制在每次迁移后调用Seed方法,如果存在行数据,则该方法更新现有数据,如果不存在,则该方法插入数据。
按下CTRL+SHIFT+B来生成项目(如果此处不执行此生成操作,后续的步骤会失败)
下一步是创建DbMigration类来初始化迁移。迁移将创建一个新的数据库,这也是在前面步骤中删除数据库文件的原因。
在程序包管理器控制台窗口,输入命令“add-migration Initial”来创建初始迁移。其中Initial可以是任意名称,用来标识创建的初始文件。控制台输出如下:
PM> add-migration Initial Scaffolding migration 'Initial'. The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration 201401140628222_Initial' again. PM>
代码先行迁移机制在Migrations文件夹下创建另外一个类文件,文件名为时间戳+下划线+Initial.cs,例如 201401140628222_Initial.cs,该类包含了创建数据库架构的代码。迁移文件名预置为时间戳有助于排序。查看该文件,包含了创建Movie库表的说明。当你更新数据库时,该类将被执行,创建数据库架构。随后,Seed方法将被执行,测试数据被添加其中。
在程序包管理器控制台窗口,键入“update-database”命令来创建数据库和执行Seed方法。
PM> update-database Specify the '-Verbose' flag to view the SQL statements being applied to the target database. Applying code-based migrations: [201401140628222_Initial]. Applying code-based migration: 201401140628222_Initial. Running Seed method. PM>
如果遇到表已存在的错误而不能创建,很可能是你删除数据库后,执行update-database前运行了应用程序(重新编译程序,自动创建了数据库)。这种情况下,再次删除数据库文件,并执行update-database命令。如果仍然出错,删除migrations目录和内容,重新开始本教程操作。
运行应用程序,导航到/Movies地址。种子数据显示出来了。
为Movie模型增加评价属性
为已存在的影片类增加评价属性。打开Models\Movie.cs文件,增加Rating属性如下
public string Rating { get; set; }
通过生成菜单或者CTRL+SHIFT+B快捷键编译应用程序。
现在我们已经更新了模型类,同样需要更新\Views\Movies\Index.cshtml和\Views\Movies\Create.cshtml视图模板。
打开\Views\Movies\Index.cshtml文件,在Price列后增加列标题<th>Rating</th>.然后在模板结尾增加<td>里标签。
其他的视图中也做相应修改,此处不再详细描述。
现在我们已经更新了程序代码来支持新增的评价属性。运行程序并导航到/Movies,我们会发现以下错误:
The model backing the 'MovieDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
发生该错误的原因是我们在程序中更新了Movie模型类,与已存在的数据库中的Movie表结构不同(数据库Movie表中没有Rating列)。
解决此问题,有以下集中方法:
A. 令Entity Framework依据新模型类架构自动删除和重新创建数据库。该方法非常适用于开发在测试数据上进行动态开发;可以是我们快速演化模型和数据库表结构。不过,其缺点是,会丢失当前数据库中已存在的数据,因此我们不想在生产数据库上使用这种方法。在测试数据库上采用初始化器来自动产生数据库通常是一种高效开发应用程序的方式。
B. 显式的修改现有的数据库结构,以便它匹配模型类。这种方法的优点是保留了现存数据。你可以通过手动或者创建一个数据库脚本来做变更。
C. 使用代码先行迁移来更新数据库架构。
在本节中,我们将使用上面所说的第三种方式,即代码先行迁移
更新Seed方法,使其为新增的列提供值。打开Migrations\Configuration.cs文件,为每个Movie对象增加Rating值。
生成解决方案,然后打开库管理器控制台窗口,输入以下命令add-migration AddRatingMig
add-migration 命令告诉迁移框架对比当前模型和库表结果差异,生成必要的代码来使库表跟模型适配。AddRatingMig名字可以是任意的,只是迁移文件的标识符,采用有意义的名字有助于迁移操作。
当命令执行完毕后,Visual Studio打开类文件,创建了新的DbMigration类,在其Up方法里,你可以看到创建新列的代码。
public partial class AddRatingMig : DbMigration { public override void Up() { AddColumn("dbo.Movies", "Rating", c => c.String()); } public override void Down() { DropColumn("dbo.Movies", "Rating"); } }
生成解决方案,库管理器控制台窗口输入“update-database”命令。
PM> update-database Specify the '-Verbose' flag to view the SQL statements being applied to the target database. Applying code-based migrations: [201401140719292_AddRatingMig]. Applying code-based migration: 201401140719292_AddRatingMig. Running Seed method. PM>
运行应用程序,导航到/Movies,你将看到新增的Rating列。
也可以在此在库管理器控制台里输入“update-database”命令,发现没有修改被应用,因为当前数据库表结构跟模型匹配。
总结:
要使用代码先行提供的迁移功能来保证模型和数据库自动匹配,需要在库程序包管理器里依次执行以下命令:
1.启用迁移功能:Enable-Migrations -ContextTypeName Mvc_Movie.Models.MovieDBContext
2.建立初态:add-migration Initial
3.自动比对差异生成迁移类:add-migration AddRatingMig
4.将迁移应用到数据库:update-database
在实际的项目开发过程或者维护过程中,因为业务需求或者设计的变动,经常需要对库表增删字段,在项目团队多人合作方式开发情况下,很容易遗漏对数据库的修改,而迁移功能就很好地保证了这一点,“自动”记录了模型变动需要对库表进行的变更操作。
本节中,我们学习了如何修改模型对象,并保持与数据库同步。同时学习了如何创建带有示例数据的数据库的方法。下一节,我们将学习如何为模型类添加验证逻辑使业务规则生效。