チュートリアル: ASP.NET MVC アプリで EF 移行を使用し、Azure にデプロイする

これまでの Contoso University のサンプル Web アプリケーションは、開発用コンピューター上の IIS Express でローカルに実行されています。 実際のアプリケーションを他のユーザーがインターネット経由で使用できるようにするには、Web ホスティング プロバイダーにデプロイする必要があります。 このチュートリアルでは、Code First の移行を有効にして、Azure のクラウドにアプリケーションをデプロイします。

  • Code First Migrations を有効にします。 移行機能を使用すると、データベースを削除して再作成することなく、データベース スキーマを更新するだけで、データ モデルを変更し、運用環境に変更をデプロイできます。
  • Azure にデプロイ。 この手順は省略可能です。プロジェクトがデプロイ済みでなくても、残りのチュートリアルを続行できます。

デプロイにはソース管理を使用した継続的インテグレーション プロセスを使用することをお勧めしますが、このチュートリアルではこれらのトピックについては説明しません。 詳細については、「Azure を使用した Real-World Cloud Apps の構築」のソース管理継続的インテグレーションの章を参照してください。

このチュートリアルでは、次の作業を行いました。

  • Code First 移行を有効にする
  • Azure にアプリをデプロイする (省略可能)

前提条件

Code First 移行を有効にする

新しいアプリケーションを開発して、データ モデルが頻繁に変更される場合、モデルが変更されるたびに、モデルはデータベースと同期されなくなります。 データ モデルを変更するたびに、データベースを自動的に削除して再作成するように Entity Framework を構成しました。 エンティティ クラスを追加、削除、または変更したり、DbContext クラスを変更したりすると、次にアプリケーションを実行する際に、既存のデータベースが自動的に削除され、モデルに一致する新しいデータベースが作成され、テスト データを用いてシードされます。

このメソッドは、実稼働環境にアプリケーションを展開するまで、データベースとデータ モデルの同期の維持がうまく機能します。 実稼働環境でアプリケーションを実行している場合、通常、保持する必要があるデータが保存され、新しい列の追加などの変更を加えるたびにすべてが失われないようにする必要があります。 Code First Migrations 機能は、データベースを削除して再作成するのではなく、Code First でデータベース スキーマを更新できるようにすることで、この問題を解決します。 このチュートリアルでは、アプリケーションをデプロイし、移行を有効にする準備をします。

  1. 前に設定した初期化子を無効にするには、Application 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
    

    enable-migrations コマンドは、ContosoUniversity プロジェクトに Migrations フォルダーを作成し、そのフォルダーに、編集して Migrations を構成するための Configuration.cs ファイルを格納します。

    (データベース名の変更が求められる上記の手順を実行していない場合、Migrations は既存のデータベースを検索し、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 メソッドを設定する

データ モデルを変更するたびにデータベースを削除して再作成する場合は、初期化子クラスの Seed メソッドを使用してテスト データを挿入します。これは、モデルの変更を行うたびにデータベースが削除され、すべてのテスト データが失われるためです。 Code First Migrations では、データベースの変更後もテスト データが保持されるため、Seed メソッドにテスト データを含める必要は通常ありません。 実際、Migrations を使用してデータベースを運用環境にデプロイする場合は、Seed メソッドでテスト データを挿入する必要はありません。運用環境で Seed メソッドが実行されるためです。 Seed メソッドで、運用環境で必要なデータのみをデータベースに挿入します。 たとえば、アプリケーションが運用環境で使用可能になったときに、データベースに実際の部署名を Department テーブルに含める場合があります。

このチュートリアルでは、デプロイに Migrations を使用しますが、大量のデータを手動で挿入しなくてもアプリケーションの機能のしくみを簡単に確認できるように、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" 操作は、既に存在する行を挿入しようとした場合に発生するエラーを防ぎますが、アプリケーションのテスト中に行った可能性のあるデータに対する変更を "オーバーライド" します。 一部のテーブルのテスト データではデータを変更したくない場合があります。テスト中にデータを変更した場合、データベースの更新後も変更を維持したいことがあります。 その場合は、条件付き挿入操作を実行します。行がまだ存在しない場合にのみ行を挿入します。 Seed メソッドは両方の方法を使用します。

    AddOrUpdate メソッドに渡される最初のパラメーターは、行が既に存在するかどうかを確認するために使用するプロパティを指定します。 指定するテスト 学生データの場合、リスト内の姓はそれぞれ一意であるため、LastName プロパティをこの目的に使用できます。

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

    このコードでは、姓が一意であることを前提としています。 姓が重複する学生を手動で追加すると、次に移行を実行するときに次の例外が発生します。

    シーケンスに複数の要素が含まれています

    "Alexander Carson" という名前の 2 人の学生などの冗長データをハンドルする方法については、Rick Anderson のブログ記事「Entity Framework (EF) DB のシード処理とデバッグ」を参照してください。 AddOrUpdate メソッドの詳細については、Julie Lerman のブログの「EF 4.3 AddOrUpdate メソッドに注意する」を参照してください。

    Enrollment エンティティを作成するコードでは、students コレクション内のエンティティに ID 値があることを前提としていますが、コレクションを作成するコードではそのプロパティを設定していません。

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

    students コレクションの SaveChanges を呼び出すときに ID 値が設定されるため、ここでは ID を使用できます。 EF は、エンティティをデータベースに挿入するときに主キー値を自動的に取得し、メモリ内のエンティティの ID プロパティを更新します。

    Enrollments エンティティ セットに各 Enrollment エンティティを追加するコードでは、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 で最初からデータベースを作成するコードが生成されました。 このコードは、[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");
    }
}

移行は、Up メソッドを呼び出して、移行のためのデータ モデルの変更を実装します。 更新をロールバックするためのコマンドを入力すると、移行が Down メソッドを呼び出します。

このコードは、add-migration InitialCreate コマンドを入力したときに作成された初期移行です。 このパラメーター (例の InitialCreate) はファイル名に使用され、任意の名前にすることができます。通常は、移行で行われることを要約した単語や語句を選択します。 たとえば、後で移行に "AddDepartmentTable" という名前を付ける可能性があります。

データベースが既に存在するときに、初期移行を作成した場合、データベースの作成コードが生成されますが、データベースは既にデータと一致しているため、作成コードを実行する必要はありません。 データベースがまだ存在しない別の環境にアプリを展開する場合、データベースを作成するために、このコードが実行されるため、最初にテストを行うことをお勧めします。 これが、移行で新しいデータベースを最初から作成できるように、前の接続文字列でデータベースの名前を変更した理由です。

  1. [パッケージ マネージャー コンソール] ウィンドウで、次のコマンドを入力します。

    update-database

    update-database コマンドは、Up メソッドを実行してデータベースを作成し、Seed メソッドを実行してデータベースを設定します。 次のセクションに示すように、アプリケーションをデプロイすると、同じプロセスが運用環境で自動的に実行されます。

  2. サーバー エクスプローラーを使用して最初のチュートリアルで行ったようにデータベースを検査し、アプリケーションを実行して、すべてが以前と同じように動作することを確認します。

Azure に展開する

これまで、アプリケーションは開発用コンピューター上の IIS Express でローカルに実行されています。 他のユーザーがインターネット経由で使用できるようにするには、Web ホスティング プロバイダーにデプロイする必要があります。 チュートリアルのこのセクションでは、Azure にデプロイします。 このセクションは省略可能です。これをスキップして次のチュートリアルに進むことも、このセクションの手順を選択した別のホスティング プロバイダーに合わせて調整することもできます。

Code First 移行を使用してデータベースをデプロイする

データベースをデプロイするには、Code First 移行 を使用します。 Visual Studio からデプロイするための設定の構成に使用する発行プロファイルを作成するときに、[データベースの更新] というラベルのチェック ボックスをオンにします。 この設定により、デプロイ プロセスは、Code First が MigrateDatabaseToLatestVersion 初期化子クラスを使用するように、移行先サーバー上のアプリケーション Web.config ファイルを自動的に構成します。

デプロイ プロセスでプロジェクトを宛先サーバーにコピーしている間、Visual Studio はデータベースに対して何も行いません。 デプロイされたアプリケーションを実行し、デプロイ後にデータベースに初めてアクセスすると、Code First はデータベースがデータ モデルと一致するかどうかを検査します。 不一致がある場合、Code First はデータベースを自動的に作成するか (まだ存在しない場合)、データベース スキーマを最新バージョンに更新します (データベースが存在するが、モデルと一致しない場合)。 アプリケーションで Migrations Seed メソッドが実装されている場合、データベースの作成後またはスキーマの更新後にこのメソッドが実行されます。

Migrations Seed メソッドはテスト データを挿入します。 運用環境にデプロイする場合は、運用データベースに挿入するデータのみを挿入するように、Seed メソッドを変更する必要があります。 たとえば、現在のデータ モデルでは、実際の授業に対し架空の学生を開発データベースに含めたい場合があります。 開発中には両方を読み込むよう Seed メソッドを記述し、運用環境にデプロイする前に架空の学生をコメントアウトできます。 または、Seed メソッドを記述して授業のみを読み込み、アプリケーションの UI を使用してテスト データベースに架空の学生を手動で入力することもできます。

Azure アカウントを取得する

Azure アカウントが必要です。 Azure アカウントをまだお持ちでなくても、Visual Studio サブスクリプションをお持ちの場合は、サブスクリプションの特典をアクティブ化できます。 それ以外の場合は、数分で無料試用版のアカウントを作成することができます。 詳細については、「Azure の無料試用版サイト」を参照してください。

Azure で Web サイトと SQL Database を作成する

Azure の Web アプリは共有ホスティング環境で実行されます。つまり、他の Azure クライアントと共有されている仮想マシン (VM) 上で実行されます。 共有ホスティング環境は、低コストでクラウドの利用を開始できる方法です。 後で Web トラフィックが増加したら、アプリケーションの規模を変更して専用 VM 上で実行するように設定してニーズを満たすことができます。 Azure App Service の価格オプションの詳細については、「App Service の価格」を参照してください。

Azure SQL データベースにデータベースをデプロイします。 Azure SQL データベースは、SQL Server テクノロジに基づいて構築されたクラウドベースのリレーショナル データベース サービスです。 SQL Server で動作するツールおよびアプリケーションは、SQL データベースでも動作します。

  1. Azure 管理ポータルの左側のタブで [リソース の作成] を選択 し、[新規] ウィンドウ (またはブレード) で [すべて表示] を選択して、使用可能なすべてのリソースを表示します。 [すべて] ブレードの [Web] セクションで [Web アプリと SQL] を選択します。 最後に、[作成] を選択します。

    Azure Portal でのリソースの作成

    新しい [Web アプリと SQL] リソースを作成するためのフォームが開きます。

  2. アプリケーションの一意の URL として使用する文字列を [アプリ名] ボックスに入力します。 完全な URL は、ここで入力したものと、Azure App Services の既定のドメイン (.azurewebsites.net) の組み合わせで構成されます。 アプリ名 が既に取得されている場合、ウィザードは「アプリ名は使用できません」というメッセージを赤色で表示します。 アプリ名が使用可能な場合は、緑色のチェックマークが表示されます。

  3. [サブスクリプション] ボックスで、App Service を配置する Azure サブスクリプションを選択します。

  4. [リソース グループ] テキスト ボックスでリソース グループを選択するか、新しいリソース グループを作成します。 この設定によって、使用する Web サイトが実行されるデータ センターが指定されます。 リソース グループの詳細については、「リソース グループ」を参照してください。

  5. [App Service] セクションをクリックして新しい App Service プランを作成し、[新規作成] をクリックし、App Service プラン (App Service と同じ名前を指定できます)、場所価格レベル (無料のオプションがあります) を入力します。

  6. [SQL Database] をクリックし、[新しいデータベースの作成] を選択するか、既存のデータベースを選択します。

  7. [名前] ボックスに、データベースの名前を入力します。

  8. [ターゲット サーバー] ボックスをクリックし、[新しいサーバーの作成] を選択します。 または、以前にサーバーを作成した場合は、使用可能なサーバーの一覧からそのサーバーを選択できます。

  9. [価格レベル] セクションを選択し、[無料] を選択します。 さらにリソースが必要な場合は、いつでもデータベースをスケールアップできます。 Azure SQL の価格の詳細については、「Azure SQL Database の価格」を参照してください。

  10. 必要に応じて照合順序を変更します。

  11. 管理者の SQL 管理者ユーザー名SQL 管理者パスワードを入力します。

    • [新しい SQL Database サーバー] を選択した場合は、後でデータベースにアクセスするときに使用する新しい名前とパスワードを定義します。
    • 以前に作成したサーバーを選択した場合は、そのサーバーの資格情報を入力します。
  12. Application Insights を使用して、App Service に対してテレメトリ コレクションを有効にすることができます。 Application Insights では最小限の構成で、重要なイベント、例外、依存関係、要求、トレースの情報を収集できます。 Application Insights の詳細については、「Azure Monitor」を参照してください。

  13. 下部にある [作成] をクリックして完了を確定させます。

    管理ポータルが [ダッシュボード] ページに戻り、ページの上部にある [通知] 領域がサイトが作成中であることを示します。 しばらくすると (通常は 1 分未満)、デプロイが成功したことを示す通知が表示されます。 左側のナビゲーション バーで、新しい App Service が [App Services] セクションに表示され、新しい SQL データベースが [SQL データベース] セクションに表示されます。

Azure にアプリケーションをデプロイする

  1. Visual Studio のソリューション エクスプローラーで、プロジェクトを右クリックし、コンテキスト メニューの [発行] をクリックします。

  2. [発行先の選択] ページで、[App Service] を選択し、[既存から選択][発行] の順に選択します。

    発行先ページを選択する

  3. Visual Studio で Azure サブスクリプションをまだ追加していない場合は、画面上の手順を実行します。 これらの手順により、Visual Studio が Azure サブスクリプションに接続し、App Services の一覧に Web サイトが含まれるようになります。

  4. [App Service] ページで、App Service を追加したサブスクリプションを選択します。 [表示] で、[リソース グループ] を選択します。 App Service を追加したリソース グループを展開し、App Service を選択します。 [OK] を選択してアプリを発行します。

  5. 出力 ウィンドウでは、実行されたデプロイ操作が表示され、デプロイが問題なく完了したことが報告されます。

  6. デプロイが成功すると、自動的に既定のブラウザーが開き、デプロイ先の Web サイトの URL にアクセスします。

    Students_index_page_with_paging

    これで、アプリはクラウドで実行されます。

[Code First 移行の実行 (アプリの起動時に実行)] を選択したため、この時点で SchoolContext データベースが Azure SQL データベースに作成されました。 デプロイされた Web サイトの Web.config ファイルが変更され、コードがデータベースに初めて読み書きするときに MigrateDatabaseToLatestVersion 初期化子が実行されるようになりました ([Students] タブを選択したときに実行されました)。

Web.config ファイルの抜粋

デプロイ プロセスでは、Code First Migrations 用の新しい接続文字列 (SchoolContext_DatabasePublish) も作成され、データベース スキーマの更新とデータベースのシード処理に使用されます。

Web.config ファイルの接続文字列

デプロイされたバージョンの Web.config ファイルは、自分のコンピューターの ContosoUniversity\obj\Release\Package\PackageTmp\Web.config にあります。デプロイされた Web.config ファイル自体には、FTP を使用してアクセスできます。 手順については、「Visual Studio を使用した ASP.NET Web デプロイ: コード更新プログラムのデプロイ」を参照してください。 「FTP ツールを使用するには、FTP URL、ユーザー名、パスワードの 3 つが必要です」で始まる手順に従います。

Note

Web アプリにはセキュリティが実装されていないため、URL を見つけたすべてのユーザーがデータを変更できます。 Web サイトを保護する方法については、「メンバーシップ、OAuth、SQL データベースを使用して安全な ASP.NET MVC アプリを Azure にデプロイする」を参照してください。 Azure 管理ポータルまたは、Visual Studio の サーバー エクスプローラー でサービスを停止し、他のユーザーがサイトを使用できなくすることができます。

App Service のメニュー項目を停止する

高度な移行シナリオ

このチュートリアルのように、移行を自動的に実行してデータベースを展開し、複数のサーバーで実行される Web サイトに展開する場合は、複数のサーバーが同時に移行を実行しようとする可能性があります。 移行はアトミックであるため、2 台のサーバーで同じ移行を実行しようとすると、1 台では成功し、もう一方は失敗します (操作は 2 回実行できない前提)。 このような問題を回避する場合は、移行を手動で呼び出し、ユーザー独自のコードを設定し、1 回だけ発生するようにします。 詳細については、Rowan Miller のブログ記事「コードからの移行の実行とスクリプト化」と Migrate.exe (コマンド ラインから移行を実行する場合) を参照してください。

その他の移行シナリオについては、「Migrations Screencast シリーズ」を参照してください。

特定の移行を更新する

update-database -target MigrationName

update-database -target MigrationName コマンドは、対象となる移行を実行します。

データベースへの移行の変更を無視する

Add-migration MigrationName -ignoreChanges

ignoreChanges で空の移行が作成され、現在のモデルがスナップショットになります。

Code First 初期化子

デプロイ セクションで、MigrateDatabaseToLatestVersion 初期化子が使用されていることを確認しました。 Code First には、CreateDatabaseIfNotExists (既定値) 、DropCreateDatabaseIfModelChanges (先ほど使用しました)、DropCreateDatabaseAlways など、他の初期化子も用意されています。 DropCreateAlways 初期化子は、単体テストの条件を設定する場合に役立ちます。 独自の初期化子を記述することもできます。また、アプリケーションがデータベースに対し読み書きを行うまで待機したくない場合は、初期化子を明示的に呼び出すことができます。

初期化子の詳細については、「Entity Framework Code First のデータベース初期化子について」および、Julie Lerman と Rowan Miller の著書『Programming Entity Framework: Code First』の第 6 章を参照してください。

コードを取得する

完成したプロジェクトをダウンロードする

その他のリソース

他の Entity Framework リソースへのリンクは、「ASP.NET データ アクセス - 推奨リソース」にあります。

次のステップ

このチュートリアルでは、次の作業を行いました。

  • Code First の移行を有効にしました
  • Azure にアプリをデプロイしました (省略可能)

次の記事に進み、ASP.NET MVC アプリケーションのより複雑なデータ モデルを作成する方法についてご覧ください。