翻訳:MVC5(5)のEntity Framework 6の使用開始-MVCプログラムでのEntity Frameworkのコード最初の移行と展開

MVCプログラムでのEntity Frameworkのコードファーストの移行と展開

これは、MVC 5シリーズを使用したMicrosoftの公式チュートリアルGetting Entity Framework 6 Code Firstの翻訳です。これは5番目の記事です。MVCプログラムでのEntity Frameworkのコードファーストの移行と展開

原文:ASP.NET MVCアプリケーションでのEntity Frameworkを使用したコードファーストの移行と配置


これまでのところ、アプリケーションはローカルマシンですでに正常に実行できます。しかし、より多くの人が使用できるようにインターネットで公開したい場合は、プログラムをWEBサーバーにデプロイする必要があります。このチュートリアルでは、Contoso UniversityアプリケーションをWindows Azure Webサイトのクラウドに展開します。

このチュートリアルには、次の章が含まれています。

  • Code First Migrationを有効にします。移行機能を使用すると、データベースのデータ構造を削除して再作成することなく、データモデルに変更を加え、変更内容を実稼働環境に展開できます。
  • アプリケーションをWindows Azureにデプロイします。このステップはオプションです。このステップをスキップして、残りのチュートリアルを続けることができます。

ソースコードで制御される継続的インテグレーションプロセスを使用してデプロイすることをお勧めしますが、このチュートリアルではこれらのトピックは扱いません。詳細については、「ソース管理」およびWindows Azureで実際のクラウドアプリを構築する」を参照してください

Code First Migrationを有効にする

新しいアプリケーションを開発すると、データモデルが頻繁に変更されます。また、変更のたびに、データモデルはデータベースから切り離されます。Entity Frameworkが正常に構成され、データモデルを変更するたびにデータベースが自動的に削除および再作成されました。エンティティクラスを追加、削除、または変更したり、DbContextクラスを変更したりすると、アプリケーションを再実行すると、既存のデータベースが自動的に削除され、現在のデータモデルと一致するデータベースが作成されます。テストデータを入力します。

このアプローチは、アプリケーションを本番環境にデプロイする準備ができるまで、データモデルとデータベーススキーマの同期を保つのに非常に適しています。アプリケーションが本番を開始して本番データを保存する場合、データモデルの変更(新しい列の追加など)によって本番データが失われることはありません。Code First Migrations関数はこの問題を解決します。データベースを削除して再構築する代わりに、Code First Migrationを有効にしてデータベーススキーマを更新します。このチュートリアルでは、アプリケーションをデプロイし、移行を有効にする準備をします。

前のチュートリアルでWeb.Configに設定した初期設定を無効にします。

<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>

また、Web.configで、データベース接続文字列の名前をContosoUniversity2に変更します。

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

この変更により、プロジェクトの最初の移行が設定され、新しいデータベースが作成されます。これは必須ではありませんが、後で行うことをお勧めします。

[ツール]メニューの[NuGetパッケージマネージャー]をクリックし、[パッケージマネージャーコンソール]をクリックします。

午後1時

コンソールで次のコマンドを入力します。

enable-migrations
add-migration InitialCreate

pmcenablemigrations

enable-migrationsコマンドは、プロジェクトに移行フォルダーを作成します。同時に、フォルダーにはConfiguration.csファイルが含まれています。このファイルを編集して、移行を構成できます。前の手順でデータベース名を変更しなかった場合は、移行によって既存のデータベースが検出され、add-migrationコマンドが自動的に実行されます。これは重要ではありません。これは、データベースを展開する前に移行コードのテストを実行しないことを意味します。その後、update-databaseを実行しても、データベースが既に存在するため、変更は行われません。

migrationsconfigfile

前のチュートリアルと同様に、SeedメソッドもConfigurationクラスに含まれています。

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メソッドを使用してテストデータを挿入できます。モデルがデータベースを変更するたびに、データベースが削除され、すべてのテストデータが失われるためです。前者のコードファーストでは、データベースが変更された後もテストデータが保持されます。したがって、通常、シードメソッドにテストデータを含める必要はありません。実際、シードメソッドは実稼働環境で呼び出されるため、移行を使用してデータベースを実稼働環境に展開するときに、シードメソッドがテストデータを挿入することは望ましくありません。この場合、シードメソッドは、本当に必要な場合にのみ、本番環境にデータを挿入するために使用されます。たとえば、運用環境に展開するときに、実際の部門名をDeparmentテーブルに含めることができます。

このチュートリアルでは、移行を使用してデプロイします。ただし、プログラム関数が手動操作なしでデータを挿入する方法を簡単に確認できるようにするために、シードメソッドを使用してテストデータを挿入します。

次のコードを使用して、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メソッドは、データベースの更新コマンドを実行するたびに実行されるため、通常、移行のたびにデータを挿入することはできません。追加しようとしている行は、データベース作成後の最初の移行ですでに存在している可能性があるためです。「upsert」操作により、既存の行を追加することはできなくなりますが、テスト段階でデータに加えた変更が書き換えられます。これを一部のデータテーブルで発生させたくない場合があります。場合によっては、テスト段階でテストデータに加えた変更を保持したいことがあります。この場合、条件付き挿入操作を行う必要があります。行が存在しない場合にのみ行を挿入します。Seedメソッドは、上記の両方のメソッドを使用します。

AddOrUpdateメソッドに渡される最初のパラメーター、指定された属性は、行がすでに存在するかどうかを確認するために使用されます。あなたが提供するテスト学生データの場合、LastName属性を使用して、エンティティが各リストで一意であるかどうかを確認できます。

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

このコードは、LastNameが一意であることを前提としています。LastNameが重複する生徒を手動で追加すると、「シーケンスに複数の要素が含まれています」という例外が発生します。簡単なデータの処理方法については、Entity Framework(EF)DBのシードとデバッグを参照してください。AddOrUpdateメソッドの詳細については、「EF 4.3 AddOrUpdateメソッドに注意してください」を参照してください。Enrollmentエンティティを作成するコードでは、学生のコレクション内のエンティティにID値が既にあると想定していますが、この値をコードで設定してコレクションを作成していません。

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

学生コレクションのSaveChangesメソッドを呼び出すときにID値が設定されるため、ここでID値を使用できます。エンティティがデータベースに挿入されると、エンティティフレームワークはエンティティの主キー値を自動的に取得し、メモリ内のエンティティのID属性を更新します。各EnrollmentエンティティをEnrollmentsエンティティコレクションに追加するコードは、AddOrUpdateメソッドを使用せず、各エンティティが存在するかどうかを確認し、存在しない場合はエンティティを挿入します。このメソッドは、アプリケーションUIを使用して成績に加えられた変更を保持します。コードは、登録リストの各メンバーをトラバースします。メンバーがデータベースに存在しない場合は、データベースに追加します。データベースを初めて更新するとき、データベースは空なので、コレクション内のすべての登録エンティティが追加されます。

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

プロジェクトをビルドします。

最初の移行を実行する

add-migrationコマンドを実行すると、移行によりデータベースを作成するコードが生成されます。このコードは、<Timestamp> _InitalCreate.csという名前のファイルのMigrationsフォルダーにもあります。このクラスの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)はファイルの名前に使用されますが、他の任意の名前にすることもできます。通常は、移行中に行われた変更を要約する単語またはフレーズを選択します。たとえば、移行に「AddDeparmentTable」という名前を付けることができる場合があります。

データベースがすでに存在する場所に移行を作成すると、生成されたデータベース作成コードは実行されません。データベースはすでにデータモデルと一致しているためです。アプリケーションがデータベースが作成されていない別の環境にデプロイされると、コードが実行されてデータベースが作成されます。したがって、事前にテストすることをお勧めします。これが、接続文字列でデータベースの名前を以前に変更した理由です。これにより、移行によって新しいデータベースを最初から作成できます。

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

update-database

データベースを更新する

update-databaseコマンドは、Upメソッドを実行してデータベースを作成し、次にSeedメソッドを実行してデータベースにデータを入力します。次のセクションで説明するように、プログラムが本番環境にデプロイされると、同じプロセスが発生します。サーバー資産管理マネージャーを使用してデータベースをチェックし、データベース内のデータとプログラムが以前と同様に実行されていることを確認します。

Windows Azureにデプロイする

Windows Azureの試用アカウントがないため、翻訳のこの部分はスキップされます...とにかく学習に影響はありません。

まとめ

このセクションでは、Code Firstを使用して移行する方法について説明しました。次のセクションでは、高度なトピックに進み、データモデルを拡張します。

著者情報

トム・ディクストラ Tom Dykstra -Tom Dykstraは、Microsoft Web Platform and Toolsチームのシニアプログラマー兼ライターです。

元の記事を40件公開 賞賛を25件 100,000回以上の閲覧

おすすめ

転載: blog.csdn.net/yym373872996/article/details/52965750