Code First 迁移
2015-06-20 22:16
453 查看
本演练将提供对实体框架中 Code First 迁移的概述。您可以完成整个演练,也可以跳至自己感兴趣的主题。主题如下:
启用迁移
生成并运行迁移
自定义迁移
数据移动和自定义 SQL
迁移到特定版本(包括降级)
生成 SQL 脚本
在应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)
在我们开始使用迁移之前,需要有一个项目和一个 Code First 模型。对于本次演练任务,我们仍将使用 Blog 和 Post 规范模型。
创建新的 MigrationsDemo 控制台应用程序
将最新版本的 EntityFramework NuGet 包添加到项目
工具 –> 库程序包管理器 –> 程序包管理器控制台
运行 Install-Package EntityFramework 命令
添加一个包含下面所示代码的 Model.cs 文件。这段代码定义一个 Blog 类,该类由我们的域模型和一个作为
EF Code First 上下文的 BlogContext 类组成。
现在我们已经有了一个模型,该使用它来执行数据访问了。用下面所示代码更新 Program.cs 文件。
运行应用程序,您会看到已为您创建 MigrationsCodeDemo.BlogContext 数据库。
如果安装了 SQL Express(包括在 Visual Studio 2010 中),则该数据库将在本地 SQL Express 实例(.\SQLEXPRESS)中创建。如果未安装
SQL Express,则 Code First 将尝试使用 LocalDb ((localdb)\v11.0) - LocalDb 包括在 Visual Studio 2012 中。
注意:如果安装有 SQL Express,则始终优先使用它,即使您在使用 Visual Studio 2012 也是如此
(LocaDb 数据库)
(SQL Express 数据库)
现在要对我们的模型进行一些更改。
让我们向 Blog 类引入一个 Url 属性。
如果您打算再次运行该应用程序,则将显示 InvalidOperationException,表明支持“BlogContext”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库 ( http://go.microsoft.com/fwlink/?LinkId=238269)。
按异常消息指示,现在应该开始使用 Code First 迁移。第一步是为上下文启用迁移。
在程序包管理器控制台中运行 Enable-Migrations 命令
此命令已为项目添加了 Migrations 文件夹,此新文件夹包含两个文件:
Configuration 类。此类允许您针对上下文配置迁移的行为。对于此演练,我们将使用默认配置。
因为在您的项目中只有一个 Code First 上下文,所以 Enable-Migrations 已自动填入要应用此配置的上下文类型中。
InitialCreate 迁移。此迁移已在启用迁移之前生成,因为我们事先让 Code First 自动创建了一个数据库。此基架迁移中的代码表示数据库中已创建的对象。在本例中,此类对象为 Blog 表,其中包含 BlogId 和 Name 列。文件名包含时间戳,这对于排序十分有帮助。
如果尚未创建数据库,则不会将此 InitialCreate 迁移添加到项目中。而是,首次调用 Add-Migration 时,用于创建这些表的代码将为新迁移搭建基架。
Code First 迁移有两个主命令,下面您将会熟悉它们。
Add-Migration 将根据自创建上次迁移以来您对模型所做的更改,为下一次迁移搭建基架。
Update-Database 将所有挂起的迁移应用于数据库。
我们需要为迁移搭建基架以处理先前添加的新 Url 属性。使用 Add-Migration 命令可以为这些迁移指定名称,我们将其称为 AddBlogUrl。
在程序包管理器控制台中运行 Add-Migration AddBlogUrl 命令。
在 Migrations 文件夹中,现在有了新的 AddBlogUrl 迁移。该迁移文件名以时间戳作为前缀,这对于排序十分有帮助。
现在,我们可以编辑此迁移或向其添加内容,一切都很不错。让我们使用 Update-Database 将此迁移应用于数据库。
在程序包管理器控制台中运行 Update-Database 命令。
Code First 迁移将对 Migrations 文件夹中的迁移与已应用于数据库的迁移进行比较。它将了解到需要应用 AddBlogUrl 迁移,于是便运行该迁移。
此时,MigrationsDemo.BlogContext 数据库已进行了更新,其 Blogs 表中包含了 Url 列。
到目前为止,我们生成并运行了迁移,而未进行任何更改。现在,让我们看一下如何编辑默认情况下生成的代码。
我们需要对模型再进行一些更改,让我们向 Blog 类添加一个新的 Rating 属性。
再添加一个新的 Post 类
我们还要向 Blog 类添加一个 Posts 集合,以在 Blog 与 Post 之间形成另一层关系。
我们将使用 Add-Migration 命令让 Code First 迁移自动在迁移时为其最佳猜测搭建基架。我们将此迁移称为 AddPostClass。
在程序包管理器控制台中运行 Add-Migration AddPostClass 命令。
Code First 迁移为这些更改搭建基架的工作做得很好,但有些内容可能需要我们更改:
首先,我们向 Posts.Title 列添加一个唯一索引
(添加到以下代码的第 22 和 29 行)。
还添加一个不可为 Null 的 Blogs.Rating 列。如果表中有任何现有数据,则这些数据将被分配采用新列数据类型的 CLR 默认值(Rating 为整数,因此默认值将为 0)。但我们想指定默认值 3,为 Blogs 表中的现有行设置一个还不错的起始等级。
(您可以在以下代码的第 24 行看到指定的默认值)
我们编辑好的迁移已准备就绪,让我们使用 Update-Database 更新数据库。这次指定 –Verbose 标记,以便您能够看见
Code First 迁移所运行的 SQL。
在程序包管理器控制台中运行 Update-Database –Verbose 命令。
到目前为止,我们了解了不更改或迁移任何数据的迁移操作,现在看一下需要来回移动一些数据的迁移操作。目前还没有为数据移动提供本机支持,但我们可以在脚本中的任何位置运行一些任意 SQL 命令。
现在向模型中添加一个 Post.Abstract 属性。随后,我们将使用 Content 列开头的一些文本为现有文章预填充 Abstract。
我们将使用 Add-Migration 命令让 Code First 迁移自动在迁移时为其最佳猜测搭建基架。
在程序包管理器控制台中运行 Add-Migration AddPostAbstract 命令。
生成的迁移负责处理架构更改,但我们还希望使用每篇文章内容的前 100 个字符预填充 Abstract 列。为此,可以向下拖到 SQL 并在添加该列后运行 UPDATE语句。
(添加到以下代码的第 12 行)。
我们编辑好的迁移很不错,让我们使用 Update-Database 更新数据库。我们将指定 –Verbose 标记,以便可以查看正在对数据库运行的
SQL。
在程序包管理器控制台中运行 Update-Database –Verbose 命令。
到目前为止,我们一直是升级到最新迁移,但有时您可能需要升级/降级到特定迁移。
假如我们希望将数据库迁移到当时运行 AddBlogUrl 迁移后所处的状态。可以使用 –TargetMigration 开关降级到此迁移。
在程序包管理器控制台中运行 Update-Database –TargetMigration: AddBlogUrl 命令。
此命令将为 AddBlogAbstract 和 AddPostClass 迁移运行
Down 脚本。
如果要一直回滚到空数据库,可以使用 Update-Database –TargetMigration: $InitialDatabase 命令。
假如其他开发人员的计算机上也需要这些更改,则在我们将所做的更改签入源代码管理后,他们只需执行同步操作即可。在他们得到我们的新迁移后,即可运行 Update-Database 命令在本地应用这些更改。不过,如果希望将这些更改推送到测试服务器并最终应用于生产,我们可能希望向 DBA 提交一个 SQL 脚本。
运行 Update-Database 命令,但此时指定 –Script 标记,使更改写入脚本而不应用。我们还将指定为其生成脚本的源和目标迁移。我们希望脚本用于从空数据库
($InitialDatabase) 最新版本(迁移 AddPostAbstract)的迁移。
如果不希望指定目标迁移,迁移将使用最新迁移作为目标。如果未指定源迁移,迁移将使用数据库的当前状态。
在程序包管理器控制台中运行 Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract 命令。
Code First 迁移将运行迁移管道,而不是实际应用更改,它会自动将更改写出到一个 .sql 文件。生成脚本后,将会自动在 Visual Studio 中打开它,以供您查看或保存。
如果您要部署应用程序,可能希望在应用程序启动时自动升级数据库(通过应用所有挂起的迁移)。可通过注册 MigrateDatabaseToLatestVersion 数据库初始值设定项来实现这一点。数据库初始值设定项只是包含用于确保数据库安装正确的某种逻辑。首次在应用程序进程 (AppDomain)
中使用上下文时,将运行此逻辑。
我们可以更新 Program.cs 文件(如下所示),先设置 BlogContext 的 MigrateDatabaseToLatestVersion 初始值设定项,然后再使用上下文(第
14 行)。请注意,您还需要为 System.Data.Entity 命名空间添加一个 using 语句(第 5 行)。
创建此初始值设定项的实例时,需要指定上下文类型 (BlogContext) 和迁移配置
(Configuration) - 迁移配置是启用迁移时添加到 Migrations 文件夹的类。
现在,每次应用程序运行时,它都会先检查所面向的数据库是否是最新的;如果不是,便会应用所有挂起的迁移。
在本演练中,您了解到如何为基于代码的迁移搭建基架、编辑和运行这些迁移,从而实现数据库的升级和降级。此外,还了解到如何获取 SQL 脚本以将迁移应用于数据库,以及如何在应用程序启动时自动应用所有挂起的迁移。
启用迁移
生成并运行迁移
自定义迁移
数据移动和自定义 SQL
迁移到特定版本(包括降级)
生成 SQL 脚本
在应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)
构建一个初始模型和数据库
在我们开始使用迁移之前,需要有一个项目和一个 Code First 模型。对于本次演练任务,我们仍将使用 Blog 和 Post 规范模型。创建新的 MigrationsDemo 控制台应用程序
将最新版本的 EntityFramework NuGet 包添加到项目
工具 –> 库程序包管理器 –> 程序包管理器控制台
运行 Install-Package EntityFramework 命令
添加一个包含下面所示代码的 Model.cs 文件。这段代码定义一个 Blog 类,该类由我们的域模型和一个作为
EF Code First 上下文的 BlogContext 类组成。
using System.Data.Entity; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Data.Entity.Infrastructure; namespace MigrationsDemo { public class BlogContext : DbContext { public DbSet<Blog> Blogs { get; set; } } public class Blog { public int BlogId { get; set; } public string Name { get; set; } } }
现在我们已经有了一个模型,该使用它来执行数据访问了。用下面所示代码更新 Program.cs 文件。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MigrationsDemo { class Program { static void Main(string[] args) { using (var db = new BlogContext()) { db.Blogs.Add(new Blog { Name = "Another Blog " }); db.SaveChanges(); foreach (var blog in db.Blogs) { Console.WriteLine(blog.Name); } } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
运行应用程序,您会看到已为您创建 MigrationsCodeDemo.BlogContext 数据库。
如果安装了 SQL Express(包括在 Visual Studio 2010 中),则该数据库将在本地 SQL Express 实例(.\SQLEXPRESS)中创建。如果未安装
SQL Express,则 Code First 将尝试使用 LocalDb ((localdb)\v11.0) - LocalDb 包括在 Visual Studio 2012 中。
注意:如果安装有 SQL Express,则始终优先使用它,即使您在使用 Visual Studio 2012 也是如此
(LocaDb 数据库)
(SQL Express 数据库)
启用迁移
现在要对我们的模型进行一些更改。让我们向 Blog 类引入一个 Url 属性。
public string Url { get; set; }
如果您打算再次运行该应用程序,则将显示 InvalidOperationException,表明支持“BlogContext”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库 ( http://go.microsoft.com/fwlink/?LinkId=238269)。
按异常消息指示,现在应该开始使用 Code First 迁移。第一步是为上下文启用迁移。
在程序包管理器控制台中运行 Enable-Migrations 命令
此命令已为项目添加了 Migrations 文件夹,此新文件夹包含两个文件:
Configuration 类。此类允许您针对上下文配置迁移的行为。对于此演练,我们将使用默认配置。
因为在您的项目中只有一个 Code First 上下文,所以 Enable-Migrations 已自动填入要应用此配置的上下文类型中。
InitialCreate 迁移。此迁移已在启用迁移之前生成,因为我们事先让 Code First 自动创建了一个数据库。此基架迁移中的代码表示数据库中已创建的对象。在本例中,此类对象为 Blog 表,其中包含 BlogId 和 Name 列。文件名包含时间戳,这对于排序十分有帮助。
如果尚未创建数据库,则不会将此 InitialCreate 迁移添加到项目中。而是,首次调用 Add-Migration 时,用于创建这些表的代码将为新迁移搭建基架。
生成并运行迁移
Code First 迁移有两个主命令,下面您将会熟悉它们。Add-Migration 将根据自创建上次迁移以来您对模型所做的更改,为下一次迁移搭建基架。
Update-Database 将所有挂起的迁移应用于数据库。
我们需要为迁移搭建基架以处理先前添加的新 Url 属性。使用 Add-Migration 命令可以为这些迁移指定名称,我们将其称为 AddBlogUrl。
在程序包管理器控制台中运行 Add-Migration AddBlogUrl 命令。
在 Migrations 文件夹中,现在有了新的 AddBlogUrl 迁移。该迁移文件名以时间戳作为前缀,这对于排序十分有帮助。
namespace MigrationsDemo.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddBlogUrl : DbMigration { public override void Up() { AddColumn("Blogs", "Url", c => c.String()); } public override void Down() { DropColumn("Blogs", "Url"); } } }
现在,我们可以编辑此迁移或向其添加内容,一切都很不错。让我们使用 Update-Database 将此迁移应用于数据库。
在程序包管理器控制台中运行 Update-Database 命令。
Code First 迁移将对 Migrations 文件夹中的迁移与已应用于数据库的迁移进行比较。它将了解到需要应用 AddBlogUrl 迁移,于是便运行该迁移。
此时,MigrationsDemo.BlogContext 数据库已进行了更新,其 Blogs 表中包含了 Url 列。
自定义迁移
到目前为止,我们生成并运行了迁移,而未进行任何更改。现在,让我们看一下如何编辑默认情况下生成的代码。我们需要对模型再进行一些更改,让我们向 Blog 类添加一个新的 Rating 属性。
public int Rating { get; set; }
再添加一个新的 Post 类
public class Post { public int PostId { get; set; } [MaxLength(200)] public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }
我们还要向 Blog 类添加一个 Posts 集合,以在 Blog 与 Post 之间形成另一层关系。
public virtual List<Post> Posts { get; set; }
我们将使用 Add-Migration 命令让 Code First 迁移自动在迁移时为其最佳猜测搭建基架。我们将此迁移称为 AddPostClass。
在程序包管理器控制台中运行 Add-Migration AddPostClass 命令。
Code First 迁移为这些更改搭建基架的工作做得很好,但有些内容可能需要我们更改:
首先,我们向 Posts.Title 列添加一个唯一索引
(添加到以下代码的第 22 和 29 行)。
还添加一个不可为 Null 的 Blogs.Rating 列。如果表中有任何现有数据,则这些数据将被分配采用新列数据类型的 CLR 默认值(Rating 为整数,因此默认值将为 0)。但我们想指定默认值 3,为 Blogs 表中的现有行设置一个还不错的起始等级。
(您可以在以下代码的第 24 行看到指定的默认值)
namespace MigrationsCodeDemo.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddPostClass : DbMigration { public override void Up() { CreateTable( "Posts", c => new { PostId = c.Int(nullable: false, identity: true), Title = c.String(maxLength: 200), Content = c.String(), BlogId = c.Int(nullable: false), }) .PrimaryKey(t => t.PostId) .ForeignKey("Blogs", t => t.BlogId, cascadeDelete: true) .Index(t => t.BlogId) .Index(p => p.Title, unique: true); AddColumn("Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3)); } public override void Down() { DropIndex("Posts", new[] { "Title" }); DropIndex("Posts", new[] { "BlogId" }); DropForeignKey("Posts", "BlogId", "Blogs"); DropColumn("Blogs", "Rating"); DropTable("Posts"); } } }
我们编辑好的迁移已准备就绪,让我们使用 Update-Database 更新数据库。这次指定 –Verbose 标记,以便您能够看见
Code First 迁移所运行的 SQL。
在程序包管理器控制台中运行 Update-Database –Verbose 命令。
数据移动/自定义 SQL
到目前为止,我们了解了不更改或迁移任何数据的迁移操作,现在看一下需要来回移动一些数据的迁移操作。目前还没有为数据移动提供本机支持,但我们可以在脚本中的任何位置运行一些任意 SQL 命令。现在向模型中添加一个 Post.Abstract 属性。随后,我们将使用 Content 列开头的一些文本为现有文章预填充 Abstract。
public string Abstract { get; set; }
我们将使用 Add-Migration 命令让 Code First 迁移自动在迁移时为其最佳猜测搭建基架。
在程序包管理器控制台中运行 Add-Migration AddPostAbstract 命令。
生成的迁移负责处理架构更改,但我们还希望使用每篇文章内容的前 100 个字符预填充 Abstract 列。为此,可以向下拖到 SQL 并在添加该列后运行 UPDATE语句。
(添加到以下代码的第 12 行)。
namespace MigrationsCodeDemo.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddPostAbstract : DbMigration { public override void Up() { AddColumn("Posts", "Abstract", c => c.String()); Sql("UPDATE Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL"); } public override void Down() { DropColumn("Posts", "Abstract"); } } }
我们编辑好的迁移很不错,让我们使用 Update-Database 更新数据库。我们将指定 –Verbose 标记,以便可以查看正在对数据库运行的
SQL。
在程序包管理器控制台中运行 Update-Database –Verbose 命令。
迁移到特定版本(包括降级)
到目前为止,我们一直是升级到最新迁移,但有时您可能需要升级/降级到特定迁移。假如我们希望将数据库迁移到当时运行 AddBlogUrl 迁移后所处的状态。可以使用 –TargetMigration 开关降级到此迁移。
在程序包管理器控制台中运行 Update-Database –TargetMigration: AddBlogUrl 命令。
此命令将为 AddBlogAbstract 和 AddPostClass 迁移运行
Down 脚本。
如果要一直回滚到空数据库,可以使用 Update-Database –TargetMigration: $InitialDatabase 命令。
获取 SQL 脚本
假如其他开发人员的计算机上也需要这些更改,则在我们将所做的更改签入源代码管理后,他们只需执行同步操作即可。在他们得到我们的新迁移后,即可运行 Update-Database 命令在本地应用这些更改。不过,如果希望将这些更改推送到测试服务器并最终应用于生产,我们可能希望向 DBA 提交一个 SQL 脚本。运行 Update-Database 命令,但此时指定 –Script 标记,使更改写入脚本而不应用。我们还将指定为其生成脚本的源和目标迁移。我们希望脚本用于从空数据库
($InitialDatabase) 最新版本(迁移 AddPostAbstract)的迁移。
如果不希望指定目标迁移,迁移将使用最新迁移作为目标。如果未指定源迁移,迁移将使用数据库的当前状态。
在程序包管理器控制台中运行 Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract 命令。
Code First 迁移将运行迁移管道,而不是实际应用更改,它会自动将更改写出到一个 .sql 文件。生成脚本后,将会自动在 Visual Studio 中打开它,以供您查看或保存。
在应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)
如果您要部署应用程序,可能希望在应用程序启动时自动升级数据库(通过应用所有挂起的迁移)。可通过注册 MigrateDatabaseToLatestVersion 数据库初始值设定项来实现这一点。数据库初始值设定项只是包含用于确保数据库安装正确的某种逻辑。首次在应用程序进程 (AppDomain)中使用上下文时,将运行此逻辑。
我们可以更新 Program.cs 文件(如下所示),先设置 BlogContext 的 MigrateDatabaseToLatestVersion 初始值设定项,然后再使用上下文(第
14 行)。请注意,您还需要为 System.Data.Entity 命名空间添加一个 using 语句(第 5 行)。
创建此初始值设定项的实例时,需要指定上下文类型 (BlogContext) 和迁移配置
(Configuration) - 迁移配置是启用迁移时添加到 Migrations 文件夹的类。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using MigrationsDemo.Migrations; namespace MigrationsDemo { class Program { static void Main(string[] args) { Database.SetInitializer(new MigrateDatabaseToLatestVersion<BlogContext, Configuration>()); using (var db = new BlogContext()) { db.Blogs.Add(new Blog { Name = "Another Blog " }); db.SaveChanges(); foreach (var blog in db.Blogs) { Console.WriteLine(blog.Name); } } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
现在,每次应用程序运行时,它都会先检查所面向的数据库是否是最新的;如果不是,便会应用所有挂起的迁移。
摘要
在本演练中,您了解到如何为基于代码的迁移搭建基架、编辑和运行这些迁移,从而实现数据库的升级和降级。此外,还了解到如何获取 SQL 脚本以将迁移应用于数据库,以及如何在应用程序启动时自动应用所有挂起的迁移。
相关文章推荐
- SVN
- BOM的来源是不可能出现的字符,GB2312双字节高位都是1,Unicode理论的根本缺陷导致UTF8的诞生
- CentOS修改SSH端口
- [BZOJ3998]TJOI2015弦论|后缀自动机
- 真机DDMS下data目录打不开——ADB server didn't ACK * failed to start daemon *||Android 查看 /data/data 目录
- 位运算---水题
- @requestparam怎么用
- 紧急情况下压缩了测试周期应该怎么办
- 我的Ubuntu/Linux配置
- C语言中fgetc()函数的返回值意义
- C#程序重启自己
- leetcode Combination Sum III
- Android之基本常见知识(持续更新)
- 对键盘弹出的处理
- JAVA8中反射获取参数名称
- Ubuntu14.04 安装Visual Studio Code
- Mysql实现行列转换
- 机房重构--UI设计与单例思考
- exploit - windbg - find "jmp esp"
- 3、上下文