Code First 遷移----官方 應用程序啓動時自動升級(MigrateDatabaseToLatestVersion 初始值設定項)

Code First 遷移

若是使用的是 Code First 工做流,推薦使用 Code First 遷移改進應用程序的數據庫架構。 遷移提供一組容許如下操做的工具:sql

  1. 建立可用於 EF 模型的初始數據庫
  2. 生成遷移以跟蹤對 EF 模型所作的更改
  3. 使數據庫隨時掌握這些更改

下方演練將概述實體框架中的 Code First 遷移。 能夠完成整個演練或跳到感興趣的主題。 包含如下主題:數據庫

生成初始模型和數據庫

開始使用遷移以前,須要會用到項目和 Code First 模型。 對於此演練,咱們將使用規範的「博客」和「帖子」模型。服務器

  • 建立新的 MigrationsDemo 控制檯應用程序
  • 將最新版本的 EntityFramework NuGet 包添加到項目中
    • 「工具」–>「庫包管理器」–>「包管理器控制檯」
    • 運行 Install-Package EntityFramework 命令
  • 添加 Model.cs 文件,其代碼以下所示。 此代碼定義了構成域模型的單個「博客」類和 EF Code First 上下文 BlogContext 類

C#架構

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 文件,其代碼以下所示。

C#app

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 數據庫。框架

    數據庫  LocalDB

啓用遷移

現可對模型進行更多更改。ide

  • 將 Url 屬性引入「博客」類。

C#工具

public string Url { get; set; }

若是要再次運行應用程序,則會收到一個 InvalidOperationException,指出「建立數據庫後,支持‘BlogContext’上下文的模型已發生變化。請考慮使用 Code First 遷移更新數據庫 (http://go.microsoft.com/fwlink/?LinkId=238269)」。測試

如異常狀況所述,可開始使用 Code First 遷移。 第一步是啓用上下文遷移。ui

  • 在包管理器控制檯中運行 Enable-Migrations 命令

    此命令已將「遷移」文件夾添加到項目中。 此新文件夾包含兩個文件:

  • 配置類。 此類容許配置遷移對上下文的行爲方式。 對於此演練,將只使用默認配置。 因爲項目中只有一個 Code First 上下文,所以 Enable-Migrations 已自動填充此配置適用的上下文類型。

  • InitialCreate 遷移。 之因此生成此遷移,是由於在啓用遷移以前,咱們已使用 Code First 建立了數據庫。 已構建的遷移中的代碼表示已在數據庫中建立的對象。 在本演練中,即爲具備 BlogId 和「名稱」列的 Blog 表。 文件名包含時間戳,這樣有助於排序。若是還沒有建立數據庫,則不會將此 InitialCreate 遷移添加到項目中。相反,第一次調用 Add-Migration 時,會將建立這些表的代碼構建到新的遷移中。

針對同一數據庫的多個模型

使用 EF6 以前的版本時,只能使用一個 Code First 模型生成/管理數據庫的架構。 這是由於每一個數據庫的單個 __MigrationsHistory 表沒法識別哪些項屬於哪一個模型。

從 EF6 開始,配置類中包括 ContextKey 屬性。 該屬性充當每一個 Code First 模型的惟一標識符。 __MigrationsHistory 表中相應的列容許來自多個模型的項共享表。 默認狀況下,此屬性設置爲上下文的徹底限定名稱。

生成和運行遷移

Code First 遷移具備兩個須要用戶瞭解的主要命令。

  • Add-Migration 將基於自上次遷移建立以來對模型所作的更改來構建下一次遷移
  • Update-Database 將對數據庫應用任意掛起的遷移

咱們須要構建遷移來處理添加的新 Url 屬性。 Add-Migration 命令可爲這些遷移命名,僅需調用 AddBlogUrl。

  • 在包管理器控制檯中運行 Add-Migration AddBlogUrl 命令
  • 現「遷移」文件夾中具備新的 AddBlogUrl 遷移。 遷移文件名以時間戳做爲前綴,這樣有助於排序

C#

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 將此遷移應用到數據庫。

  • 在包管理器控制檯運行 Update-Database 命令
  • Code First 遷移將比較「遷移」文件夾中的遷移和已應用於數據庫的遷移。 遷移會發現需應用 AddBlogUrl 遷移,並運行它。

MigrationsDemo.BlogContext 數據庫現已更新,其中包含「博客」表中的 Url 列。

自定義遷移

到目前爲止,咱們已在未進行任何更改的狀況下生成並運行了遷移。 如今咱們來看看如何編輯默認生成的代碼。

  • 如今可對模型進行更多更改,咱們將新的 Rating 屬性添加到「博客」類

C#

public int Rating { get; set; }
  • 同時添加一個新的「帖子」類

C#

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; }
    }
  • 此外,再將「帖子」集合添加到「博客」類,以造成「博客」和「帖子」之間的另外一層關係

C#

public virtual List<Post> Posts { get; set; }

使用 Add-Migration 命令使 Code First 遷移提供對遷移的最佳猜想 咱們將調用此遷移 AddPostClass。

  • 在包管理器控制檯中運行 Add-Migration AddPostClass 命令。

Code First 遷移出色的構建了這些更改,但咱們可能還須要作出一些更改:

  1. 首先,將惟一索引添加到 Posts.Title 列(添加在如下代碼的 22 和 29 行)。
  2. 同時添加不可爲 NULL 的 Blogs.Rating 列。 若是表中存在任何現有數據,則會爲數據分配新列數據類型的 CLR 默認值(分級是整數,所以將爲 0)。 但咱們要將默認值指定爲 3,以便「博客」表中的現有行以合適的分級開始。 (能夠看到如下代碼的第 24 行指定的默認值)

C#

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" });
                DropIndex("dbo.Posts", new[] { "BlogId" });
                DropForeignKey("dbo.Posts", "BlogId", "dbo.Blogs");
                DropColumn("dbo.Blogs", "Rating");
                DropTable("dbo.Posts");
            }
        }
    }

已編輯的遷移準備就緒,因此咱們使用 Update-Database 來更新數據庫。 此次指定 –Verbose 標誌,以即可以看到 Code First 遷移正在運行的 SQL。

  • 在包管理器控制檯中運行 Update-Database –Verbose 命令。

數據移動/自定義 SQL

到目前爲止,咱們已經介紹了不更改或移動任何數據的遷移操做,如今來看看須要移動數據的操做。 目前尚未對數據移動的原生支持,但咱們能夠在腳本中的任何位置運行一些任意 SQL 命令。

  • 將 Post.Abstract 屬性添加到模型中。 稍後,咱們將使用「內容」列開頭的一些文本預填充現有帖子的「摘要」。

C#

public string Abstract { get; set; }

使用 Add-Migration 命令使 Code First 遷移提供對遷移的最佳猜想

  • 在包管理器控制檯中運行 Add-Migration AddPostAbstract 命令。
  • 生成的遷移會處理架構更改,但咱們仍是但願使用每一個帖子內容的前 100 個字符預填充「摘要」列。 要執行此操做,可在添加列以後下拉到 SQL 並運行 UPDATE 語句。 (添加在如下代碼的第 12 行中)

C#

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

已編輯的遷移一切正常,因此咱們可以使用 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 中打開,以供查看或保存。

生成冪等腳本

從 EF6 開始,若是指定 –SourceMigration $InitialDatabase,則生成的腳本將爲「冪等」。 冪等腳本能夠將當前任何版本的數據庫升級到最新版本(或使用 – TargetMigration 升級到指定版本)。 生成的腳本包括檢查 __MigrationsHistory 表的邏輯,而且僅應用之前未應用的更改。

應用程序啓動時自動升級(MigrateDatabaseToLatestVersion 初始值設定項)

若是要部署應用程序,則可能但願應用程序在啓動時自動升級數據庫(經過應用各類掛起的遷移)。 能夠經過註冊 MigrateDatabaseToLatestVersion 數據庫初始值設定項來執行此操做。 數據庫初始值設定項僅包含一些用於確保正確設置數據庫的邏輯。 第一次在應用程序進程中使用上下文時,會運行此邏輯 (AppDomain)。

以下所示,能夠更新 Program.cs 文件,以在使用上下文(第 14 行)以前,爲 BlogContext 設置 MigrateDatabaseToLatestVersion 初始化值設定項。 請注意,還須要爲 System.Data.Entity 命名空間(第 5 行)添加 using 語句。

建立此初始值設定項的實例時,須要指定上下文類型 (BlogContext) 和遷移配置(配置)- 遷移配置是啓用遷移時添加到「遷移」文件夾的類

C#

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

如今,每當應用程序運行時,它首先會檢查其目標數據庫是否爲最新,若是不是,則會應用各類掛起的遷移。

原文連接:https://docs.microsoft.com/zh-cn/ef/ef6/modeling/code-first/migrations/index

相關文章
相關標籤/搜索