Entity Framework Code First -- Migrations 迁移
在开始使用迁移(Migrations)之前,我们需要一个 Project 和一个 Code First Model, 对于本文将使用典型的 Blog 和 Post 模型
- 创建一个新的控制台应用程序 MigrationsDemo;
- 添加最新的 EntityFramework 到项目
- Tools –> Library Package Manager –> Package Manager Console;
- 运行命令 Install-Package EntityFramework
- 创建 Blog.cs 和 DbContext 的派生类 BlogContext.cs
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
更改 Program.cs 以调用

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();
}

运行查看结果

发现如上错误"CREATE DATABSE permission denied in databse 'master'"
我们在 BlogContext 上的无参构造函数上添加诊断代码并设置调试断点
System.Diagnostics.Debug.Write(Database.Connection.ConnectionString);
再次运行

我们注意到 Data Scource 竟然是 .\\SQLEXPRESS 而不是我们想要的 localDB , 这是因为:
- 如果我们安装了 SQL Express,那么 database 将会安装在 local SQL Express instance,否则 Code First 才将尝试使用 localDB;
- SQL Express 总是具有优先权,只要安装了它
知道了原因我们就好解决了:
- 如果想继续使用 SQL Express,那么就配置相应地权限,请参考 http://odetocode.com/Blogs/scott/archive/2012/08/14/a-troubleshooting-guide-for-entity-framework-connections-amp-migrations.aspx;
- 如果想改用 localDB, 只需在.config 配置即可(放在 configSections 节点后面)
<connectionStrings>
<add name="BlogContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=BlogContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
</connectionStrings>
再次运行就行了,让我们看一下后台生成的数据库

启用迁移
我们对模型 Blog 做一些更改:增加一个 Url 属性
public string Url { get; set; }
我们此时再次运行程序,发现如下错误

'InvalidOperationException' was unhandled. The model backing the 'BlogContext' context has changed since the database was created. Consider using Code First Migrations to update the database ( http://go.microsoft.com/fwlink/?LinkId=238269)
正如错误消息提示的那样,是时候使用 Code First Migrations,第一步是运行如下的命令:
- 在 Package Manager Console 下运行命令 Enable-Migrations


这个命令将在项目下创建文件夹 Migrations
- The Configuration class 这个类允许你去配置如何迁移,对于本文将使用默认的配置(在本文中因为只有一个 Context, Enable-Migrations 将自动对 context type 作出适配);
- An InitialCreate migration (本文为 201312240822431_InitialCreate.cs)这个迁移之所以存在是因为我们之前用 Code First 创建了数据库, 在启用迁移前,scaffolded migration 里的代码表示在数据库中已经创建的对象,本文中即为表 Blog (列 BlogId 和Name). 文件名包含一个 timestamp 以便排序(如果之前数据库没有被创建,那么 InitialCreate migration 将不会被创建,相反,当我们第一次调用 Add-Migration 的时候所有表都将归集到一个新的 migration 中)
多个实体锁定同一数据库
当使用 EF6 之前的版本时,只会有一个 Code First Model 被用来生成/管理数据库的 Schema, 这将导致每个数据库只会有一张 __MigrationsHistory 表,从而无法辨别实体与模型的对应关系。
从 EF6 开始,Configuration 类将会包含一个 ContextKey 属性,它将作为每一个 Code First Model 的唯一标识符, __MigrationsHistory 表中一个相应地的列允许来自多个模型(multiple models)的实体共享表(entries),默认情况下这个属性被设置成 context 的完全限定名。
生成、运行迁移
Code First Migrations 有两个你需要熟悉的命令:
- Add-Migration 将 scaffold 创建下一次基于上一次迁移以来的更改的迁移;
- Update-Databse 将任何挂起的迁移应用到数据库
我们需要脚手架(scaffold 直译)一个迁移,以上面的 Url 属性为例,命令 Add-Migration 允许我们对迁移命名,我们姑且称之为 AddBlogUrl
- 在 Package Manager Console 中运行命令 Add-Migration AddBlogUrl;
- 一个新的迁移(名称包含 timestamp 前缀)在目录 Migrations 中创建成功



namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddBlogUrl : DbMigration
{
public override void Up()
{
AddColumn("dbo.Blogs", "Url", c => c.String());
} public override void Down()
{
DropColumn("dbo.Blogs", "Url");
}
}
}

我们现在可以对这个迁移进行编辑或者增加,但似乎看起来还不错,那我们就直接用 Update-Database 来应用到数据库吧
- 在 Package Manager Console 中运行命令 Update-Database ;
- AddBlogUrl 迁移将会被应用到数据库(表 Blogs 增加一列 Url)


定制化迁移
到目前为止我们生成并运行了一个迁移,但是没有对迁移做任何更改,下面我们将尝试做一些更改:在类 Bolg 上增加一属性 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 中添加 Post 的集合
public virtual ICollection<Post> Posts { get; set; }
在 Package Manager Console 中运行命令 Add-Migration AddPostClass
生成的迁移如下
接下来我们对迁移做些更改:
- 在 Posts.Title 列上增加唯一索引;
- 使 Blogs.Rating 列非空,对于表中已经存在的数据,新列都会被赋值成 CLR 的默认数据类型(如 Rating 是整型,故默认值为0),但是我们想指定默认值为3,这样存在的记录将会有一个合理的评分。
更改后的代码如下

namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddPostClass : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.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("dbo.Blogs", t => t.BlogId, cascadeDelete: true)
.Index(t => t.BlogId)
.Index(p => p.Title, unique: true); AddColumn("dbo.Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
} public override void Down()
{
DropIndex("dbo.Posts", new[] { "Title" });
DropForeignKey("dbo.Posts", "BlogId", "dbo.Blogs");
DropIndex("dbo.Posts", new[] { "BlogId" });
DropColumn("dbo.Blogs", "Rating");
DropTable("dbo.Posts");
}
}
}

在 Package Manager Console 中运行命令 Update-Database –Verbose


数据移动 / 定制SQL
迄今为止,迁移都没有更改或移动数据,现在让我们看一下需要移动数据的例子。虽然没有对数据移动的原生支持,但是我们可以随意运行SQL 脚本。
让我们在 Post 中增加一个属性 Abstract, 稍后我们使用列 Content 的开头来填充此列(数据库已有记录)
public string Abstract { get; set; }
- 在 Package Manager Console 中运行命令 Add-Migration AddPostAbstract ;
- 生成的迁移非常好,但是我们想使用 Content 的前 100 个字符来预填充 Abstract 列,我们可对迁移做如下更改

namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddPostAbstract : DbMigration
{
public override void Up()
{
AddColumn("dbo.Posts", "Abstract", c => c.String());
Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
} public override void Down()
{
DropColumn("dbo.Posts", "Abstract");
}
}
}

在 Package Manager Console 中运行命令 Update-Database –Verbose
迁移至指定版本(包括后退)
迄今为止,我们总是升级至最新迁移,然而某些时候我们需要升级/降级至指定版本,例如我们想迁移数据库至运行 AddBlogUrl 迁移之后的状态,此时我们就可以使用 –TargetMigration 来降级到这个版本
在 Package Manager Console 中运行命令 Update-Database –TargetMigration: AddBlogUrl

这个命令将会运行 AddBlogAbstract and AddPostClass 的 Down 命令
如果你想回滚一切至空数据库,可以使用命令 Update-Database –TargetMigration: $InitialDatabase

得到SQL脚本
如果其它开发人员也希望在他们自己的机器上拥有这些更改,他们只需在我们 check in 代码至 source control 的时候做一次同步即可,一旦他们拥有了这些迁移,只需运行命令 Update-Database 就可以把这些更改应用于本地。但是如果我们想把这些更改推送至测试服务器或生产服务器,我们也许需要一份 SQL 脚本提供给 DBA
- 在运行 Update-Database 的时候指定 -Specify 标记,我们就能够使得这些更改被写入一个脚本中而不是被应用,我们同时也会为此脚本指定源迁移和目标迁移,例如我们希望产生的脚本是从一个空数据库($InitialDatabase)到最新的版本(AddPostAbstract 迁移);(注意:如果你没有指定目标迁移,那么迁移将始终更新至最新版本;如果你没有指定源迁移,那么迁移将以数据库目前状态为初始)
- 在 Package Manager Console 中运行命令 Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract

产生的 SQL 脚本如下
产生幂等脚本(EF6+)
从 EF6 开始,如果你使用 –SourceMigration $InitialDatabase, 产生的脚本将是幂等的,幂等脚本意味着无论数据库当前处于什么版本/状态,都能升级至最新版本或指定版本(指定 –TargetMigration),生成的脚本包括检查表 __MigrationsHistory 的逻辑以及只更新之前从未更新的
在应用程序启动时自动升级(MigrateDatabaseToLatestVersion初始化器)
当你发布部署应用程序的时候,可能希望当程序启动的时候它自动更新数据库(更新应用任何未更新的迁移),你可以通过注册 MigrateDatabaseToLatestVersion 数据库初始化器来实现这一点,数据库初始化器只包含一些逻辑检查用于确保数据库被正确设置,这个逻辑检查将会在AppDomain 的 context 第一次被使用的时候执行。
当我们创建一个初始化器的实例时,需要指定 context type(BlogContext)以及 migrations configuration (Configuration)- 这个迁移配置类是在我们启用迁移时生成的 Migrations 目录下增加的


using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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();
}
}
}

原文:http://msdn.microsoft.com/en-us/data/jj591621
Entity Framework Code First -- Migrations 迁移的更多相关文章
- Entity Framework Code First 数据迁移
需要在[工具 --> NuGet 程序包管理器 --> 程序包管理器控制台]中输入三个命令: Enable-Migrations (初次迁移时使用) Add-Migration [为本次迁 ...
- Asp.net Mvc Entity Framework Code First 数据库迁移
1.创建Mvc项目 2.安装Entity Framework 2.1.如下图打开程序包管理器控制台: 2.2.输入命令Install-Package EntityFramework,即可安装Entit ...
- Entity Framework Code First学习系列目录
Entity Framework Code First学习系列说明:开发环境为Visual Studio 2010 + Entity Framework 5.0+MS SQL Server 2012, ...
- Entity Framework Code First学习系列
Entity Framework Code First学习系列目录 Entity Framework Code First学习系列说明:开发环境为Visual Studio 2010 + Entity ...
- Entity Framework Code First 迁移
Entity Framework CodeFirst数据迁移 http://www.cnblogs.com/aehyok/p/3325459.html Entity Framework Code Fi ...
- Entity Framework Code first(转载)
一.Entity Framework Code first(代码优先)使用过程 1.1Entity Framework 代码优先简介 不得不提Entity Framework Code First这个 ...
- [转]Using Entity Framework (EF) Code-First Migrations in nopCommerce for Fast Customizations
本文转自:https://www.pronopcommerce.com/using-entity-framework-ef-code-first-migrations-in-nopcommerce-f ...
- SQLITE WITH ENTITY FRAMEWORK CODE FIRST AND MIGRATION
Last month I’ve a chance to develop an app using Sqlite and Entity Framework Code First. Before I st ...
- ASP.NET CORE系列【六】Entity Framework Core 之数据迁移
原文:ASP.NET CORE系列[六]Entity Framework Core 之数据迁移 前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framew ...
随机推荐
- To the end
身为一名初二狗的我也走过了半年.不管怎么说人生中也没有几个半年嘛.从九月到现在快四个月了,我也离中考越来越近了/郁闷/.但是还是要好好过唔.不过我想起这半学期还是挺充实的,至少没有浪费太多的时间.有些 ...
- 如何安装chrome扩展?比如json-handle插件如何安装
chrome插件安装方法: 方式一,在线安装 直接插到json-handle地址,添加即可 https://chrome.google.com/webstore/detail/json-handle/ ...
- CODE[VS]-寻找子串位置-字符串处理-天梯青铜
题目描述 Description 给出字符串a和字符串b,保证b是a的一个子串,请你输出b在a中第一次出现的位置. 输入描述 Input Description 仅一行包含两个字符串a和b 输出描述 ...
- 【ARM】S5PV210芯片中的BL0的作用
S5PV210芯片中的BL0的作用:(1)关闭看门狗:(2)清除指令寄存器:(3)初始化栈区域:(4)初始化堆区域:(5)初始化块设备复制功能:(6)初始化PLL和设置系统时钟:(7)拷贝BL1到片内 ...
- HDU 5877 Weak Pair
$dfs$序,线段树. 可以统计每一个节点作为$root$的子树上对答案的贡献,可以将树转换成序列.问题就变成了一段区间上求小于等于某个值的数有几个.用线段树记录排好序之后的区间序列,询问的时候,属于 ...
- 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群(转载-2)
原文:http://www.cnblogs.com/PurpleDream/p/4510279.html 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群 前言: ...
- 序列化与反序列化总结(Serializable和Parcelable)
序列化是指将对象的状态信息转换为可以存储或传输的形式的过程. 在Java中创建的对象,只要没有被回收就可以被复用,但是,创建的这些对象都是存在于JVM的堆内存中,JVM处于运行状态时候,这些对象可以复 ...
- video标签MP4兼容chrome问题
video标签的用法如下 <video width="320" height="240" controls> <source src=&quo ...
- LeetCode 328. Odd Even Linked List C#
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note her ...
- Introduction to Programming Contests (stanford)
http://web.stanford.edu/class/cs9http://web.stanford.edu/class/cs97si/7si/