来自:MSDN:Code First 迁移,完全照搬!
本演练将提供对实体框架中 Code First 迁移的概述。您可以完成整个演练,也可以跳至自己感兴趣的主题。主题如下:
- 启用迁移
- 生成并运行迁移
- 自定义迁移
- 数据移动和自定义 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();
}
}
}
现在,每次应用程序运行时,它都会先检查所面向的数据库是否是最新的;如果不是,便会应用所有挂起的迁移。
MSDN:Code First 迁移的更多相关文章
-
Entity Framework Code First 迁移
Entity Framework CodeFirst数据迁移 http://www.cnblogs.com/aehyok/p/3325459.html Entity Framework Code Fi ...
-
Code First 迁移,及迁移错误
迁移错误: 今天在使用EF6 Code First时,出现如下错误,折腾了老半天.分享一下,帮后面的兄弟少走弯路. PM> Enable-Migrations Checking if the c ...
-
Code First 迁移
https://msdn.microsoft.com/zh-cn/data/jj591621 Data Access and Storage > 学习 > Entity Framework ...
-
使用migrate.exe执行EF code first 迁移
Code First 迁移可用于从 Visual Studio 内部更新数据库,但也可通过命令行工具 migrate.exe 来执行.本页简单介绍如何使用 migrate.exe 对数据库执行迁移. ...
-
C# 使用Code First迁移更新数据库
三步完成迁移: 1. 启用迁移: Enable-Migrations Enable-Migrations -ContextTypeName Mvc4WebSite.Models.MvcGuestboo ...
-
支持“***Context”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库(http://go.microsoft.com/fwlink/?LinkId=238269)。
在用VS进行MVC开发的过程中遇到如下问题: 支持“***Context”上下文的模型已在数据库创建后发生更改.请考虑使用 Code First 迁移更新数据库(http://go.microsoft ...
-
用 MVC 5 的 EF6 Code First 入门 系列:MVC程序中实体框架的Code First迁移和部署
用 MVC 5 的 EF6 Code First 入门 系列:MVC程序中实体框架的Code First迁移和部署 这是微软官方SignalR 2.0教程Getting Started with En ...
-
";ApplicationDbContext";(泛指之类的数据库上下文模型)上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库。
一,在我使用自动生成数据库的时候,当你改变了数据库就会出现下面问题 "ApplicationDbContext"(泛指之类的数据库上下文模型)上下文的模型已在数据库创建后发生更改. ...
-
C# EntityFramework Code First 迁移 降级 回退到空数据库
C# EntityFramework Code First 迁移 降级 回退到空数据库 1.包管理器控制台-迁移 在包管理器控制台中运行 Enable-Migrations Add-Migratio ...
随机推荐
-
伪Textatea的构建(div+table),以及相应的滚动条问题与safari上的优化
在页面中创建一个不可编辑的文本块,并且文本块的篇幅较大,第一反应是创建一个textarea,并将它的disabled="disabled",并设置相应的scroll属性,就可以构建 ...
-
jsp的开发模式
JSP 存在两种 开发模式1.Model1 : JSP + JavaBean * 不适合开发业务逻辑特别复杂web应用 ----- 业务逻辑复杂,控制代码多,而在jsp中编写控制代码,十分不便 *JS ...
-
centos系统修改网络配置注意事项
这也是无意之中发现的,我在做一个远程修改工控机网络配置的程序, 网络配置参数/etc/sysconfig/network-scripts/ifcfg-enp1s0下面,当然名字可能不一样ifcfg-e ...
-
CSS margin 外边距 属性的位置关系
padding:内边距 margin :外边距 margin:10px; 所有 4 个外边距都是 10px ******************************************* ma ...
-
使用Spring配置数据源JdbcTemplate
c3p0作为演示 1.编写资源文件(db.properties) jdbc.user=root jdbc.password=root jdbc.jdbcUrl=jdbc:mysql://localho ...
-
Linux下java开发环境配置总结
1 安装JDK,卸载以前的jdk,安装jdk1.8 : 参考:http://www.jb51.net/os/RedHat/73016.html 需要注意配置环境变量中的路径要和当前安装的jdk路径一致 ...
-
mybatis的插件,挺好支持下
利用 Mybatis-generator自动生成代码http://www.cnblogs.com/yjmyzz/p/4210554.html Mybatis 通用 Mapper3 https://gi ...
-
Vue2.5开发去哪儿网App 第四章笔记 上
一 . 组件细节知识点 1. 解决组件在h5中编码规范 例如 : table , ul , ol 等等 <table> <tbody> <row></r ...
-
基于Java的三种对象持久化方式
1:序列化技术: 序列化的过程就是将对象写入字节流和从字节流中读取对象.将对象状态转换成字节流之后,可以用java.io包中的各种字节流类将其保存到文件中,可以通过管道或线程读取,或通过网络连接将对象 ...
-
1001. A+B Format (20)的解题思路以及多源代码文件的尝试编写
前言 这几天刚学了多源代码文件的编译,因为想尝试使用一下这种方法,所以想用此编写这次作业的程序.正好可以learning by doing,在做当中学习新知识.(编译器为Dev-C++) github ...