代码改变世界

Entity Framework4.3 Code-First基于代码的数据迁移讲解

2012-08-09 15:28  小白哥哥  阅读(4227)  评论(11编辑  收藏  举报

前段时间一直在研究Entity Framework4,但是苦于没有找到我特别中意的教程,要么就是千篇一律的文章,而且写的特别简单,可以说,糟践了微软这么牛埃克斯的东西,要么就是写的东一句西一句,估计是学习的过程中做的笔记就直接公布了,只有本人能看懂,昨天,在MSDN Blog找到一些英文文章,真的感觉老外研究东西没有咱们国内一些人那样浮躁,我倒不是崇洋媚外,但是看他们的文章确实让人感觉进步很快(包括英语,我英语和我俄罗斯语水平差不多吧),这篇文章就简单基于一篇关于Code-Based的数据迁移的英文讲解,加一些我自己的理解进入,文章末尾我会给出原文连接。由于本文是对数据迁移进行讲解,所以我在示例过程中尽量减少其他一些EF的内容混进来,比如约定,复杂类型等等,也让看到这篇文章的人能更直接的了解到数据迁移的使用方法和用处。

         这一节,主要讲在使用Entity Framework4.3 Code-First时,在VS2010中,使用代码的方式进行数据迁移,其实我个人认为这个数据迁移(Migration)并不适合于直译成中文,因为这其实是Entity Framework中的一个概念或者说很重要的一个功能。无论如何,当你看完这篇博客以后,就会理解他的意思啦。

    本文假定您对Entity Framework4.3有基础的理解,如果您还没有达到这个层次,推荐您先简单了解以下它,这段时间,我会写一个系列关于EF的文章出来的,也希望各位码友支持吧。

1.建立一个最初的模型和数据库

在使用数据迁移(Magration)之前,我们需要建立一个项目和一个Code-First模型,在本文将使用经典的Blog和Post模型,

      1.创建一个名为MigrationWorkthrough的控制台应用程序

      2.在项目中添加最新版本的Entity Framework的引用。

              在项目名中点击,Add Library Package Reference…,左侧选项卡选择Online,搜索中输入“Entity Framework”,搜索结果中点击安装。

image

             在VS2010中点击“工具”-Library Package Manager –> Package Manager Console.在打开的控制台中,输入“Install-Package EntityFramework”,回车执行,就会发现在项目引用中添加了Entity Framework的引用(还有其他,和本文无关,暂时不做解释)。

image

image

         3.在项目中添加一个Model.cs类文件,但是删除默认生成的Model类,我们添加一个Blog类作为领域模型,和一个BlogContext类作为Entity Framework Code-First的上下文。

using System;
using System.Data.Entity;
 
namespace MigrationWorkthrough
{
    /// <summary>
    /// 领域模型
    /// </summary>
    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }
    }
 
 
 
    /// <summary>
    /// Entity Framework上下文
    /// </summary>
    public class BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
    }  
}

                      4.现在,我们拥有了一个模型,是时候去执行数据访问啦,修改Program.cs中的Main方法

static void Main(string[] args)
        {
            using (BlogContext blogContext = new BlogContext())
            {
                Blog blog = new Blog { BlogId = 1, Name = "Xiaoyaojian" };
                blogContext.Blogs.Add(blog);
                blogContext.SaveChanges();
            }
        }
 

在这里需要注意,在我们使用命令添加Entity Framework的引用的时候,在我们的应用程序中生成了App.config文件,在defaultConnectionFactory节点下可以看到一个数据库连接字符串,它默认连接本机的Express数据库,请根据实际情况进行修改。

            5.编译运行应用程序,然后打开数据库管理器,可以看到生成了一个名为MigrationWorkthrough.BlogContext数据库,并且数据库下存在了与Blog领域模型对应结构的表

image

   2.启动Migration(数据迁移)

1.现在 我们在Blog类中加入Url属性

public class Blog
{
      public int BlogId { get; set; }
      public string Name { get; set; }
      public string Url { get; set; }
}

2.假如我们现在运行应用程序,将会收到一个异常,因为数据库已经不再匹配领域模型类Blog

3.依据异常中的信息,我们是使用使用Code-First Migrations啦,第一步是打开当前Context的migrations功能

         在PM命令中,执行“Enable-Migrations”命令

4.这个命令会在项目中添加一个Migrations文件夹,通常,这个文件夹下此时会包含两个文件

image

3.第一个数据迁移

Code-First Rigrations有两个你应该相当熟悉的命令

  • Add-Migration  基于现有你对模型的修改进行下一次的数据迁移
  • Update-Database 将任何待定的改变应用到数据库中

1.我们将把新添加的Url属性做数据迁移,我们使用上面介绍的Add-Migration命令,这个命令允许我们为当前的数据迁移命名,我们就叫它AddBlogUrl

  • 在PM命令中执行‘Add-Migration AddBlogUrl’

2.在Migrations文件加中,出现了一个以“当前时间戳_上面的名字.cs”命名的文件

namespace MigrationWorkthrough.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.现在在PM命令中,执行Update-Database把更改应用到数据库中

image

4.订制的数据迁移

到目前位置,我们生成并且运行的代码没有经过任何更改,现在让我们试着订制这些操作

1.现在更改Blog类,并且增加Post类,这将产生一个外键关系

using System;
using System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace MigrationWorkthrough
{
    /// <summary>
    /// 领域模型
    /// </summary>
    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; }
    }

    


    /// <summary>
    /// Entity Framework上下文
    /// </summary>
    public class BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
    }  
}
 

2.现在,让我们使用Add-Migration猜测我们的更改并将更改应用到脚手架中,我们给这次的更改起一个名字叫“AddPostClass”

  • 在PM命令中执行“Add-Migration AddPostClass”

3.Code First Migrations做了一件极好的工作就是在脚手架中添加了这些操作,但是现在我们有些东西需要更改:

  • 首先,我们要为Posts表的Title列添加一个唯一索引
  • 我们还要为Blog表的Rating列添加一个不可为空的属性,加入在这个表里存在属于,他将分配一个模型的CLR数据类型的值给他(因为Rating是Int型的,所以默认值是0),但是我们想分配一个默认值为3,以便于在Blog表里存在的数据距行有一个恰当的等级

这样,我们就来修改生成的的***_AddPostClass.cs文件,对默认生成的修改我将会加粗表示

namespace MigrationWorkthrough.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.我们更改多的Migration看起来很符合我们的心意,所以,让我们使用Update-Database将更改应用到数据库吧,这次让我们指定一个“-Verbose”的标记,以至于我们在执行Code First Migrations时候可以看见执行的SQL语句

  • 在PM命令里执行“Update-Database -Verbose”

4.动态数据/自定义SQL

直到现在。我们已经看到Migration操作不更改或者移动任何数据,现在,让我们看看有些时候我们需要移动一些数据该怎么做,Entity Framework没有对动态数据原生的支持,但是我们可以通过在我们的脚本中执行一些专用的Sql命令来完成这些操作

1.让我们在Post表中添加一个Abstract属性,然后,我们将要使用Content列的一些文本预填充Abstract。

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; }
    public string Abstract { get; set; }
}

2.让我们使用Add-Migration命令添加更改,我们给它起个名字叫“AddPostAbstract”

  • 在PM命令中执行“Add-Migration AddPostAbstract”

3.生成的Migration中已经观察到了架构的更改,但是我们需要使用Content列开头的100个文字预填充它,我们可以通过在列添加以后运行一个Update语句来达到这样的效果

namespace MigrationWorkthrough.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.现在执行“Update-Database”让更改应用到数据库,我们再次使用Verbose标记查看执行的SQL语句

5.迁移到指定版本(包括降级)

到目前位置,我们总是更行到最新的版本,但是我们有事可能需要升级或者降级到指定的版本

假设我们需要将目前的等级降级到我们执行名为AddBlogUrl的迁移的等级的时候,我们可以使用 -TargetMigration喧杂我们要降级的迁移,我们就可以这么做

  • 在PM命令中执行“Update-Database –TargetMigration:”AddBlogUrl”  ”

加入我们想让回滚所有的操作到最终空数据库的时候,我们可以通过运行“Update-Database –TargetMigration:$InitialDatabase  ”命令来得到效果

 

6。得到SQL脚本

假如另外一个开发人员想把这些更改应用到他们自己的机器上,他们只可以从我们的源代码管理中获取我们的更改,一旦他们得到我们新的Migrations,他们仅仅可以通过Update-Database命令去把更改应用到本地,然而,加入我们想把这些更改移动到一个测试服务器上或者最终生产环境中,我们可能需要一个SQL脚本教导我们的DBA手上。

1.让我们运行Update-Database命令,但是这次,我们指定一个 -Script标记,以至于更改可以写到一个脚本中而不是应用它,我们也可以指定一个源和一个目标的迁移版本来生成脚本,例如我们想得到从原始的空数据库开始到最后版本(migration “AddPstAbstract”)的脚本,我们就可以这么做

  • 在PM命令中执行“Update-Database -Script -SourceMigration:$InitialDatabase -TargetMigration:"AddPostAbstract"    ”

2.Code First Migrations将运行数据迁移流程,但是它将把这些代码输出到一个SQL文件中并且在VS中打开等待我们查看或者保存,取代之前我们一直看到的直接应用。

 

本文多内容数翻译自:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx