原文地址:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx
原文名称:EF 4.3 Code-Based Migrations Walkthrough
准备工作
在开始之前,我们需要一个项目,以及一个 Code First 的模型,对于这次演示,我们使用典型的博客 Blog 和回复 Post 模型。
1. 创建新的 MigrationsCodeDemo 控制台应用程序
2. 为项目添加最新版本的 EntityFramework NuGet 包。
找到包管理器控制台。
运行 Install-Package EntityFramework 命令。
成功之后的项目文件如下:
创建初始的模型和数据库
1. 增加如下的 Model.cs 文件,代码定义了一个单个的 Blog 类表示我们的模型对象,BlogContext 类就是 EF Code First 的上下文。
using System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;
namespace MigrationsCodeDemo
{
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
}
}
2. 现在我们已经有了一个模型,是时候进行一次数据访问了。使用如下的代码更新 Program.cs 文件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MigrationsCodeDemo
{
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);
}
}
}
}
}
3. 运行程序,现在就可以在你本地的 SQLExpress 数据库中看到数据库了。
启用迁移
1. 在 Blog 类中增加一个 Url 属性。
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
}
2. 现在运行程序,会看到如下的异常。
未经处理的异常:
System.InvalidOperationException: 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).
3. 正如异常建议,现在是开始使用 Code First 迁移的时候了,第一步是为我们的上下文启用迁移支持。
在包管理器的控制台中执行命令:Enable-Migrations
4. 这个命令在项目中增加名为 Migrations 文件夹,文件夹中包含两个文件。
Configuration 类,这个类允许你配置你的上下文的迁移行为,在这个演示中,我们仅仅使用默认配置。
因为在这个项目中只有一个上下文,Enable-Migrations 自动填充应用的这个上下文。
201202171353373_InitialCreate.cs 中的 InitialCreate ,生成这个迁移是因为我们已经通过 Code First 创建了一个数据库。这个迁移中的代码表示我们已经创建的数据库,
namespace MigrationsCodeDemo.Migrations
{
using System.Data.Entity.Migrations;
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"Blogs",
c => new
{
BlogId = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.BlogId);
}
public override void Down()
{
DropTable("Blogs");
}
}
}
第一个迁移
你会使用到两个命令
Add-Migration,将会基于你对模型的修改创建一个迁移的脚手架。
Update-Database,将没有提交的修改提交到数据库。
1. 我们首先为我们新增加的 Url 属性创建一个迁移,Add-Migration 会帮我们完成这个工作,我们为这个迁移命名为:AddBlogUrl。
执行:Add-Migration AddBlogUrl
项目中增加了一个文件
201202171413369_AddBlogUrl.cs
内容如下:
namespace MigrationsCodeDemo.Migrations
{
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");
}
}
}
3. 我们可以在这个迁移中编辑或者增加内容,但是现在看起来就很不错,让我们将这个迁移提交到数据库中。
执行: Update-Database
4. 现在的数据库中已经包含了 Url 列。
定制迁移
下面我们看看如何定制迁移。
1. 在代码中增加一个回复的类 Post,同时在 Blog 中增加一个评分属性。
using System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;
namespace MigrationsCodeDemo
{
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public int Rating { get; set; }
public List<Post> Posts { get; set; }
}
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; }
}
}
2. 使用 Add-Migration 命令创建一个迁移,命名为 AddPostClass。
3. Code First Migrations 帮我们创建好了一个迁移,但是我们希望能增加如下的修改:
首先,为 Posts.Title 增加一个唯一索引。
增加一个非空的 Blogs.Rating 列,如果表中已经存在了数据,那么就将 CLR 默认的数据类型值赋予新增加的列 (Rating 是整数类型,应该就是 0), 但是,我们希望默认为 3, 这样已经存在的博客会有一个不错的评分。
namespace MigrationsCodeDemo.Migrations
{
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[] { "BlogId" });
DropForeignKey("Posts", "BlogId", "Blogs");
DropColumn("Blogs", "Rating");
DropTable("Posts");
}
}
}
4. 运行 Update-Database 提交到数据库,这次可以使用一个参数 -Verbose,以便可以看到生成的 SQL 脚本。
数据操作/定制 SQL
我们已经完成的迁移并没有修改或者移动任何数据,我们可以在迁移中的任何地点运行任意脚本。
1. 在模型上增加一个摘要 PostAbstrack 属性,然后,希望使用已经发布的内容来填充这个摘要属性。
public class Post
{
public int PostId { get; set; }
[MaxLength(200)]
public string Title { get; set; }
public string Content { get; set; }
public string Abstract { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
2. 创建一个迁移。
3. 修改生成的迁移文件,
namespace MigrationsCodeDemo.Migrations
{
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");
}
}
}
4. 更新数据库之后,就会得到最新的数据了。使用 Verbose 参数可以看到提交的脚本。