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


Code First 遷移

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

  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#

    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

啟用遷移

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

  • 將 Url 屬性引入“博客”類。

C#

    public string Url { get; set; }

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

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

  • 在包管理器控制台中運行 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM