共用方式為


教學課程:在 ASP.NET MVC 應用程式中使用 EF 遷移並部署到 Azure

到目前為止,Contoso 大學範例 Web 應用程式已在開發電腦上的 IIS Express 中本地運行。 要讓真正的應用程式可供其他人透過 Internet 使用,您必須將其部署到 Web 託管提供者。 在本教學課程中,您將啟用 Code First 遷移並將應用程式部署到 Azure 中的雲端:

  • 啟用 Code First 遷移。 遷移功能可讓您變更資料模型,並透過更新資料庫架構將變更部署到生產環境,而無需刪除並重新建立資料庫。
  • 部署至 Azure。 此步驟是可選的;您可以繼續學習其餘教學課程,而無需部署該專案。

我們建議您使用具有原始程式碼控制的持續整合流程進行部署,但本教學課程不涵蓋這些主題。 有關詳細信息,請參閱使用 Azure 構建真實世界的雲端應用程式的開放原始碼控制持續整合章節。

在本教學課程中,您已:

  • 啟用 Code First 遷移
  • 在 Azure 中部署應用程式 (可選)

必要條件

啟用 Code First 遷移

在開發新的應用程式時,您的資料模型會頻繁變更,而每次模型變更時,模型會與資料庫不同步。 您已將實體框架設定為在每次變更資料模型時自動刪除並重新建立資料庫。 當您新增、刪除或變更實體類別或變更您的 DbContext 類別時,下次執行應用程式時,它會自動刪除現有資料庫,建立與模型相符的新資料庫,並使用測試資料為其播種。

在您將應用程式部署到生產環境之前,都可以使用上述方法讓資料庫與資料模型保持同步。 當應用程式在生產中運行時,它通常會儲存您想要保留的資料,並且您不希望每次進行更改 (例如添加新列) 時都丟失所有內容。 Code First 遷移功能透過啟用 Code First 更新資料庫架構而不是刪除並重新建立資料庫來解決此問題。 在本教學課程中,您將部署應用程序,並為此做好準備,您將啟用遷移。

  1. 透過註解或刪除新增至應用程式 Web.config 檔案的 contexts 元素來停用您先前設定的初始值設定項目。

    <entityFramework>
      <!--<contexts>
        <context type="ContosoUniversity.DAL.SchoolContext, ContosoUniversity">
          <databaseInitializer type="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity" />
        </context>
      </contexts>-->
      <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
        <parameters>
          <parameter value="v11.0" />
        </parameters>
      </defaultConnectionFactory>
      <providers>
        <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      </providers>
    </entityFramework>
    
  2. 另外,在應用程式 Web.config 檔案中,將連接字串中的資料庫名稱變更為 ContosoUniversity2。

    <connectionStrings>
      <add name="SchoolContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
    </connectionStrings>
    

    此變更設定項目,以便第一次遷移建立新資料庫。 這不是必需的,但稍後您會明白為什麼這是一個好主意。

  3. 從 [工具] 功能表中,選取 [NuGet 套件管理員]> [套件管理員主控台]

  4. PM> 提示符號處輸入以下命令:

    enable-migrations
    add-migration InitialCreate
    

    該命令在 ContosoUniversity 專案中建立一個 Migrations 資料夾,並在該資料夾中放入一個 Configuration.cs 文件,您可以編輯該文件來設定 enable-migrationsMigrations

    (如果您錯過了上面指示您更改資料庫名稱的步驟,遷移將找到現有資料庫並自動執行 add-migration 命令。沒關係,這只是意味著您在部署資料庫之前不會運行遷移代碼的測試稍後,當您執行 update-database 命令時,不會發生任何事情,因為資料庫已經存在。)

    開啟 ContosoUniversity\Migrations\Configuration.cs 檔案。 與您之前看到的初始化器 Configuration 類別一樣,該類別包含一個 Seed 方法。

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
    

    Seed 方法的目的是讓您能夠在 Code First 建立或更新資料庫後插入或更新測試資料。 建立資料庫時以及每次資料模型變更後更新資料庫架構時都會呼叫該方法。

設定種子方法

當您為每次資料模型變更刪除並重新建立資料庫時,您可以使用初始值設定項目類別的 Seed 方法插入測試資料,因為每次模型變更後,資料庫都會被刪除,所有測試資料都會遺失。 透過 Code First 遷移,測試資料會在資料庫變更後保留,因此通常不需要在 Seed 方法中包含測試資料。 事實上,如果您將使用遷移將資料庫部署到生產環境,您不希望 Seed 方法插入測試資料,因為 Seed 方法將在生產環境中運行。 在這種情況下,您希望 Seed9 方法僅將生產中所需的資料插入資料庫。 例如,當應用程式在生產中可用時,您可能希望資料庫在 Department 資料表中包含實際的部門名稱。

在本教學課程中,您將使用遷移進行部署,但您的 Seed 方法無論如何都會插入測試資料,以便更輕鬆地了解應用程式功能如何運作,而無需手動插入大量資料。

  1. Configuration.cs 檔案的內容替換為以下程式碼,這會將測試資料載入到新資料庫中。

    namespace ContosoUniversity.Migrations
    {
        using ContosoUniversity.Models;
        using System;
        using System.Collections.Generic;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
            {
                var students = new List<Student>
                {
                    new Student { FirstMidName = "Carson",   LastName = "Alexander", 
                        EnrollmentDate = DateTime.Parse("2010-09-01") },
                    new Student { FirstMidName = "Meredith", LastName = "Alonso",    
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Arturo",   LastName = "Anand",     
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Yan",      LastName = "Li",        
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Peggy",    LastName = "Justice",   
                        EnrollmentDate = DateTime.Parse("2011-09-01") },
                    new Student { FirstMidName = "Laura",    LastName = "Norman",    
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
                        EnrollmentDate = DateTime.Parse("2005-08-11") }
                };
                students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
                context.SaveChanges();
    
                var courses = new List<Course>
                {
                    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
                    new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
                    new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
                    new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
                    new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
                    new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
                    new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
                };
                courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
                context.SaveChanges();
    
                var enrollments = new List<Enrollment>
                {
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").ID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").ID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
                foreach (Enrollment e in enrollments)
                {
                    var enrollmentInDataBase = context.Enrollments.Where(
                        s =>
                             s.Student.ID == e.StudentID &&
                             s.Course.CourseID == e.CourseID).SingleOrDefault();
                    if (enrollmentInDataBase == null)
                    {
                        context.Enrollments.Add(e);
                    }
                }
                context.SaveChanges();
            }
        }
    }
    

    Seed 方法將資料庫上下文物件作為輸入參數,方法中的程式碼使用該物件為資料庫新增實體。 對於每種實體類型,程式碼都會建立新實體的集合,將它們新增到適當的 DbSet 屬性,然後將變更儲存到資料庫。 不必像這裡所做的那樣在每組實體之後呼叫 SaveChanges 方法,但如果在程式碼寫入資料庫時發生例外狀況,這樣做可以幫助您找到問題的根源。

    某些插入資料的語句使用 AddOrUpdate 方法來執行「upsert」操作。 由於 Seed 方法在您每次執行 update-database 命令時 (通常是在每次遷移之後) 運行,因此您不能只插入資料,因為您嘗試添加的行在建立資料庫的第一次遷移之後就已經存在了。 「upsert」操作可以防止在嘗試插入已存在的行時發生的錯誤,但它會覆寫您在測試應用程式時可能對資料所做的任何變更。 表格中有測試資料時,您可能不希望發生上述情況:某些案例中,如果您在測試時變更資料,可能會希望資料庫更新後變更仍保留下來。 在這種情況下,您想要執行條件插入操作:僅當行尚不存在時才插入行。 種子方法同時使用這兩種方法。

    傳遞給 AddOrUpdate 方法的第一個參數指定用於檢查行是否已存在的屬性。 對於您提供的測試學生資料,LastName 屬性可用於此目的,因為列表中的每個姓氏都是唯一的:

    context.Students.AddOrUpdate(p => p.LastName, s)
    

    此代碼假定姓氏是唯一的。 如果您手動新增姓氏重複的學生,則下次執行遷移時將會出現以下例外狀況:

    序列包含多個元素

    有關如何處理冗餘資料 (例如兩個名為「Alexander Carson」的學生) 的信息,請參閱 Rick Anderson 部落格上的播種和偵錯實體框架 (EF) DB。 有關 AddOrUpdate 方法的詳細信息,請參閱 Julie Lerman 部落格上的 Take care with EF 4.3 AddOrUpdate Method

    建立 Enrollment 實體的程式碼假定您擁有集合中實體的 ID 值,儘管您沒有在建立 students 集合的程式碼中設定該屬性。

    new Enrollment { 
        StudentID = students.Single(s => s.LastName == "Alexander").ID, 
        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
        Grade = Grade.A 
    },
    

    您可以在此處使用 ID 屬性,因為 ID 值是在您呼叫 students 集合時設定的 SaveChanges。 當 EF 將實體插入資料庫時,會自動取得主鍵值,並更新記憶體中實體的 ID 屬性。

    將每個 Enrollment 實體新增至 Enrollments 實體集的程式碼不使用 AddOrUpdate 方法。 它檢查實體是否已存在,如果不存在則插入該實體。 此方法將保留您使用應用程式 UI 對註冊成績所做的更改。 該程式碼循環遍歷Enrollment清單中的每個成員,如果在資料庫中找不到該註冊,則會將該註冊新增至資料庫。 第一次更新資料庫時,資料庫將為空,因此它將添加每個註冊。

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.ID == e.Student.ID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    
  2. 組建專案。

執行第一次遷移

當您執行 add-migration 命令時,遷移會產生從頭開始建立資料庫的程式碼。 此程式碼也位於 Migrations 資料夾中名為 <timestamp_>InitialCreate.cs 的檔案中。 InitialCreate 類別的 Up 方法會建立與資料模型實體集對應的資料庫表,並且 Down 方法會刪除它們。

public partial class InitialCreate : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.Course",
            c => new
                {
                    CourseID = c.Int(nullable: false),
                    Title = c.String(),
                    Credits = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.CourseID);
        
        CreateTable(
            "dbo.Enrollment",
            c => new
                {
                    EnrollmentID = c.Int(nullable: false, identity: true),
                    CourseID = c.Int(nullable: false),
                    StudentID = c.Int(nullable: false),
                    Grade = c.Int(),
                })
            .PrimaryKey(t => t.EnrollmentID)
            .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
            .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
            .Index(t => t.CourseID)
            .Index(t => t.StudentID);
        
        CreateTable(
            "dbo.Student",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    LastName = c.String(),
                    FirstMidName = c.String(),
                    EnrollmentDate = c.DateTime(nullable: false),
                })
            .PrimaryKey(t => t.ID);
        
    }
    
    public override void Down()
    {
        DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
        DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
        DropIndex("dbo.Enrollment", new[] { "StudentID" });
        DropIndex("dbo.Enrollment", new[] { "CourseID" });
        DropTable("dbo.Student");
        DropTable("dbo.Enrollment");
        DropTable("dbo.Course");
    }
}

Migrations 會呼叫 Up 方法,以實作移轉所需的資料模型變更。 當您輸入命令以復原更新時,Migrations 會呼叫 Down 方法。

這是您輸入 add-migration InitialCreate 命令時所建立的初始遷移。 參數 (範例中 InitialCreate) 用於文件名,可以是任何你想要的;您通常會選擇一個單字或短語來總結遷移中正在執行的操作。 例如,您可以將稍後的移轉命名為 "AddDepartmentTable"。

如果在您建立初始移轉時資料庫已經存在,系統會產生資料庫建立程式碼,但不需要執行,因為資料庫已經符合資料模型。 當您將應用程式部署到資料庫尚未存在的其他環境中時,即會執行這個程式碼以建立您的資料庫;建議您先進行測試。 這就是您之前更改連接字串中的資料庫名稱的原因,以便遷移可以從頭開始建立新資料庫。

  1. 套件管理器控制台視窗中,輸入以下命令:

    update-database

    update-database 命令運行建立資料庫的 Up 方法,然後運行填充資料庫的 Seed 方法。 部署應用程式後,相同的過程將在生產中自動運行,如您將在下一節中看到的。

  2. 使用伺服器資源管理器檢查資料庫,就像在第一個教學課程中所做的那樣,然後執行應用程式以驗證一切是否仍然像以前一樣工作。

部署至 Azure

到目前為止,該應用程式已在您的開發電腦上的 IIS Express 中本地運行。 為了使其可供其他人透過 Internet 使用,您必須將其部署到網站託管提供者。 在本教學課程的這一部分中,您將把它部署到 Azure。 此部分是可選的;您可以跳過此步驟並繼續學習以下教學課程,也可以根據您選擇的不同託管提供者調整本節中的說明。

使用 Code First 遷移來部署資料庫

要部署資料庫,您將使用 Code First 遷移。 建立用於設定從 Visual Studio 進行部署的設定的發佈設定檔時,您將選取標記為更新資料庫的核取方塊。 此設定會導致部署過程自動設定目標伺服器上的應用程式 Web.config 文件,以便 Code First 使用 MigrateDatabaseToLatestVersion 初始化程序類別。

在將專案複製到目標伺服器的部署過程中,Visual Studio 不會對資料庫執行任何操作。 當您執行已部署的應用程式並且它在部署後首次存取資料庫時,Code First 會檢查資料庫是否與資料模型相符。 如果不匹配,Code First 會自動建立資料庫 (如果尚不存在) 或將資料庫架構更新為最新版本 (如果資料庫存在但與模型不匹配)。 如果應用程式實作遷移 Seed 方法,則該方法在建立資料庫或更新架構後運行。

您的 Migrations Seed 方法會插入測試資料。 如果您要部署到生產環境,則必須變更 Seed 方法,以便它只插入您想要插入到生產資料庫中的資料。 例如,在目前的資料模型中,您可能希望開發資料庫中有真實的課程,但有虛構的學生。 您可以編寫一個 Seed 方法來在開發中載入兩者,然後在部署到生產之前註解掉虛構的學生。 或者,您可以編寫一個僅載入課程的 Seed 方法,並使用應用程式的 UI 手動在測試資料庫中輸入虛構的學生。

取得 Azure 帳戶

您需要一個 Azure 帳戶。 如果您還沒有 Visual Studio 訂閱,但有 Visual Studio 訂閱,則可以 啟動您的訂閱權益。 否則,您只需幾分鐘即可建立免費試用帳戶。 如需詳細資料,請參閱 Azure 免費試用

在 Azure 中建立網站和 SQL 資料庫

Azure 中的 Web 應用程式將在共用託管環境中執行,這表示它會在與其他 Azure 用戶端共用的虛擬機器 (VM) 上執行。 共享託管環境是一種在雲端起步的低成本方式。 稍後,如果您的 Web 流量增加,應用程式可以透過在專用虛擬機器上運行來擴展以滿足需求。 要了解有關 Azure 應用程式服務定價選項的更多信息,請閱讀應用程式服務定價。

您將把資料庫部署到 Azure SQL 資料庫。 SQL 資料庫是基於 SQL Server 技術建構的基於雲端的關聯式資料庫服務。 適用於 SQL Server 的工具和應用程式也可適用於 SQL 資料庫。

  1. Azure 管理入口網站中,選擇左側標籤中的建立資源,然後選擇新建窗格 (或側邊欄標籤) 上的查看全部以查看所有可用資源。 在 Everything 側邊欄標籤的 Web 部分中選擇 Web 應用程式 + SQL。 最後,選擇建立

    在 Azure 入口網站中建立資源

    將開啟用於建立新的新 Web 應用程式 + SQL 資源的表單。

  2. 應用程式名稱方塊中輸入字串,用作應用程式的唯一 URL。 完整的 URL 將包含您在此輸入的內容以及 Azure 應用程式服務的預設網域 (.azurewebsites.net)。 如果應用程式名稱已被佔用,精靈會以紅色訊息通知您應用程式名稱不可用。 如果應用程式名稱可用,您會看到一個綠色的複選標記。

  3. 訂閱方塊中,選擇希望應用程式服務駐留在其中的 Azure 訂閱。

  4. 資源組文字方塊中,選擇一個資源組或建立一個新資源組。 此設定指定您的網站將在哪個資料中心運行。 有關資源組的詳細信息,請參閱資源組。

  5. 透過點擊應用服務方案部分、新建來建立新的 App Service 方案,然後填寫應用程式服務計劃(可與應用程式服務名稱相同)、位置定價層 (有免費選項)。

  6. 按一下 SQL 資料庫,然後選擇建立新資料庫或選擇現有資料庫。

  7. 名稱方塊中,輸入資料庫的名稱。

  8. 按一下目標伺服器框,然後選擇建立新伺服器。 或者,如果您之前建立了伺服器,則可以從可用伺服器清單中選擇該伺服器。

  9. 選擇定價層部分,選擇免費。 如果需要額外的資源,可以隨時擴展資料庫。 要了解有關 Azure SQL 定價的更多信息,請參閱 Azure SQL 資料庫定價

  10. 根據需要修改排序規則。

  11. 輸入管理員 SQL 管理員使用者名稱SQL 管理員密碼

    • 如果選擇新 SQL Database 伺服器,請定義稍後存取資料庫時將使用的新名稱和密碼。
    • 如果您選擇了先前建立的伺服器,請輸入該伺服器的憑證。
  12. 可以使用 Application Insights 為應用程式服務啟用遙測收集。 只需很少的設定,Application Insights 即可收集有價值的事件、例外狀況、依賴項、請求和追蹤資訊。 要了解有關 Application Insights 的更多信息,請參閱 Azure Monitor

  13. 點擊底部的建立以表明您已完成。

    管理入口網站返回儀表板頁面,頁面頂部的通知區域顯示網站正在建立。 一段時間後 (通常不到一分鐘),就會出現部署成功的通知。 在左側導覽列中,新的應用服務將顯示在應用程式服務部分,新的 SQL 資料庫將顯示在 SQL 資料庫部分。

將應用程式部署至 Azure

  1. 在 Visual Studio 中,以滑鼠右鍵按一下解決方案資源管理器中的項目,然後從上下文功能表中選擇發佈

  2. 選擇發布目標頁面上,選擇應用程式服務,然後選擇現有,然後選擇發布

    選擇發布目標頁面

  3. 如果您之前未在 Visual Studio 中新增 Azure 訂閱,請執行螢幕上的步驟。 這些步驟使 Visual Studio 能夠連接到你的 Azure 訂閱,以便應用程式服務清單將包含你的網站。

  4. 應用程式服務頁面上,選擇您新增應用程式服務的訂閱。 在檢視下,選擇資源組。 展開您新增應用程式服務的資源群組,然後選擇應用程式服務。 選擇確定以發布應用程式。

  5. 輸出視窗顯示所採取的部署操作並報告部署成功完成。

  6. 成功部署後,預設瀏覽器會自動開啟已部署網站的 URL。

    Students_index_page_with_paging

    您的應用程式現在正在雲端中運行。

此時,已在 Azure SQL 資料庫中建立 SchoolContext 資料庫,因為您選擇了執行程式碼優先遷移(在應用程式啟動時執行)。 已部署網站中的 Web.config 檔案已更改,以便在程式碼第一次在資料庫中讀取或寫入資料時執行 MigrateDatabaseToLatestVersion 初始值設定項目 (當您選擇學生標籤時發生):

Web.config 檔案摘錄

部署程序也為 Code First 遷移建立了一個新的連接字串 (SchoolContext_DatabasePublish),用於更新資料庫架構和為資料庫設定種子。

Web.config 檔案中的連接字串

您可以在自己的電腦上的 ContosoUniversity\obj\Release\Package\PackageTmp\Web.config 中找到 Web.config 檔案的部署版本。您可以使用 FTP 存取已部署的 Web.config 檔案本身。 如需說明,請參閱使用 Visual Studio 進行 ASP.NET Web 部署:部署程式碼更新。 按照以「要使用 FTP 工具,您需要三件事:FTP URL、使用者名稱和密碼」開頭的說明進行操作。

注意

該網頁應用程式不實現安全性,因此任何找到該 URL 的人都可以更改資料。 有關如何保護網站安全性的說明,請參閱將具有成員資格、OAuth 和 SQL 資料庫的安全性 ASP.NET MVC 應用程式部署至 Azure。 您可以透過使用 Azure 管理入口網站或 Visual Studio 中的伺服器資源管理器停止服務來阻止其他人使用網站。

停止應用程式服務選單項

進階遷移場景

如果您透過自動執行遷移來部署資料庫 (如本教學課程所示),並且要部署到在多個伺服器上執行的網站,則可能會有多個伺服器嘗試同時執行遷移。 遷移是原子性的,因此如果兩台伺服器嘗試執行相同的遷移,一台伺服器將成功,另一台伺服器將失敗 (假設操作不能執行兩次)。 在這種情況下,如果您想避免這些問題,您可以手動呼叫遷移並設定自己的程式碼,以便它只發生一次。 有關詳細信息,請參閱 Rowan Miller 部落格上的從程式碼執行和編寫遷移指令碼以及 Migrate.exe (用於從命令列執行遷移)。

有關其他遷移方案的信息,請參閱遷移截圖系列

更新具體遷移

update-database -target MigrationName

update-database -target MigrationName 命令運行目標遷移。

忽略對資料庫的遷移更改

Add-migration MigrationName -ignoreChanges

使用目前模型作為快照 ignoreChanges 建立一個空遷移。

程式碼優先初始化器

在部署部分,您看到正在使用 MigrateDatabaseToLatestVersion 初始值設定項目。 Code First 還提供其他初始化程序,包括 CreateDatabaseIfNotExists (預設)、DropCreateDatabaseIfModelChanges (您之前使用過) 和 DropCreateDatabaseAlwaysDropCreateAlways 初始化程序對於設定單元測試的條件非常有用。 您也可以編寫自己的初始值設定項,如果您不想等到應用程式讀取或寫入資料庫,則可以明確呼叫初始值設定項。

有關初始化程序的更多信息,請參閱 Understanding Database Initializers in Entity Framework Code First 和 Julie Lerman 和 Rowan Miller 合著的編程實體框架:Code First 一書的第 6 章。

取得程式碼

下載已完成的項目

其他資源

可以在 ASP.NET 資料存取 - 推薦資源中找到其他實體框架資源的連結。

下一步

在本教學課程中,您已:

  • 啟用 Code First 遷移
  • 在 Azure 中部署應用程式 (可選)

繼續閱讀下一篇文章,了解如何為 ASP.NET MVC 應用程式建立更複雜的資料模型。