ASP.NET MVC アプリケーションの Entity Framework データ モデルの作成 (1/10)

作成者: Tom Dykstra

注意

このチュートリアル シリーズの新しいバージョンは、Visual Studio 2013、Entity Framework 6、MVC 5 で使用できます。

Contoso University サンプル Web アプリケーションでは、Entity Framework 5 と Visual Studio 2012 を使用して mvc 4 アプリケーション ASP.NET 作成する方法を示します。 サンプル アプリケーションは架空の Contoso University の Web サイトです。 学生の受け付け、講座の作成、講師の割り当てなどの機能が含まれています。 このチュートリアル シリーズでは、Contoso University サンプル アプリケーションをビルドする方法について説明します。

Code First

Entity Framework でデータを操作する方法には、 データベースファーストModel First、 Code First の 3 つの方法があります。 このチュートリアルは Code First 用です。 これらのワークフローの違いと、シナリオに最適なものを選択する方法に関するガイダンスについては、「 Entity Framework 開発ワークフロー」を参照してください。

MVC

サンプル アプリケーションは、 ASP.NET MVC 上に構築されています。 ASP.NET Web Forms モデルを使用する場合は、「モデル バインドとWeb Formsチュートリアル シリーズ」および「データ アクセス コンテンツ マップ ASP.NET する」を参照してください。

ソフトウェア バージョン

チュートリアルに示されている また、 で動作します。
Windows 8 Windows 7
Visual Studio 2012 Visual Studio 2012 Express for Web。 VS 2012 または VS 2012 Express for Web がまだない場合、これは Windows Azure SDK によって自動的にインストールされます。 Visual Studio 2013は機能するはずですが、チュートリアルはテストされておらず、一部のメニュー選択とダイアログ ボックスが異なります。 Windows Azure のデプロイには 、VS 2013 バージョンの Windows Azure SDK が必要です。
.NET 4.5 表示される機能のほとんどは .NET 4 で動作しますが、機能しないものもあります。 たとえば、EF での列挙型のサポートには .NET 4.5 が必要です。
Entity Framework 5
Windows Azure SDK 2.1 Windows Azure のデプロイ手順をスキップする場合は、SDK は必要ありません。 新しいバージョンの SDK がリリースされると、リンクによって新しいバージョンがインストールされます。 その場合は、一部の手順を新しい UI と機能に適応させる必要がある場合があります。

質問

チュートリアルに直接関連しない質問がある場合は、ASP.NET Entity Framework フォーラム、Entity Frameworkおよび LINQ to Entities フォーラム、または StackOverflow.com に投稿できます。

謝辞

VB に関する確認とメモについては、シリーズの最後のチュートリアルを参照してください。

Contoso University Web アプリケーション

一連のチュートリアルで作成するアプリケーションは、簡単な大学向け Web サイトです。

ユーザーは学生、講座、講師の情報を見たり、更新したりできます。 次のような画面をこれから作成します。

Students_Index_page

サンプルの Contoso University Web アプリケーションの [学生] 検索ページと [新しい学生の作成] ページを示すスクリーンショット。

このサイトの UI スタイルは、組み込みテンプレートで生成されるスタイルに近いものになっています。それにより、このチュートリアルでは主に、Entity Framework の使い方を取り上げることができます。

前提条件

このチュートリアルの指示とスクリーン ショットでは、 2013 年 7 月時点で最新の更新プログラムと Azure SDK for .NET がインストールされた Visual Studio 2012 または Visual Studio 2012 Express for Web を使用していることを前提としています。 このすべてを取得するには、次のリンクを使用します。

Azure SDK for .NET (Visual Studio 2012)

Visual Studio がインストールされている場合は、上記のリンクで不足しているコンポーネントがインストールされます。 Visual Studio がない場合は、リンクによって Visual Studio 2012 Express for Web がインストールされます。 Visual Studio 2013を使用できますが、必要な手順と画面の一部が異なります。

MVC Web アプリケーションを作成する

Visual Studio を開き、 ASP.NET MVC 4 Web アプリケーション テンプレートを使用して、"ContosoUniversity" という名前の新しい C# プロジェクトを作成します。 .NET Framework 4.5 をターゲットにしていることを確認します (プロパティを使用enumし、.NET 4.5 が必要です)。

New_project_dialog_box

[ 新しい ASP.NET MVC 4 プロジェクト ] ダイアログ ボックスで、[ インターネット アプリケーション ] テンプレートを選択します。

Razor ビュー エンジンは選択したままにし、[単体テスト プロジェクトの作成チェック] ボックスはオフのままにします。

[OK] をクリックします。

Project_template_options

サイト スタイルを設定する

簡単な変更をいくつか行い、サイトのメニュー、レイアウト、ホーム ページを決めます。

Views\Shared\_Layout.cshtml を開き、ファイルの内容を次のコードに置き換えます。 変更が強調表示されます。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Contoso University</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    </head>
    <body>
        <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Contoso University", "Index", "Home")</p>
                </div>
                <div class="float-right">
                    <section id="login">
                        @Html.Partial("_LoginPartial")
                    </section>
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Students", "Index", "Student")</li>
                            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
                            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
                            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
        <footer>
            <div class="content-wrapper">
                <div class="float-left">
                    <p>&copy; @DateTime.Now.Year - Contoso University</p>
                </div>
            </div>
        </footer>

        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)
    </body>
</html>

このコードにより、次の変更が行われます。

  • "My ASP.NET MVC Application" と "your logo here" のテンプレート インスタンスを "Contoso University" に置き換えます。
  • チュートリアルの後半で使用するアクション リンクをいくつか追加します。

Views\Home\Index.cshtml で、ファイルの内容を次のコードに置き換えて、ASP.NET と MVC に関するテンプレート段落を削除します。

@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
        </div>
    </section>
}

Controllers\HomeController.cs で、次の例に示すように、Action メソッドの Index の値ViewBag.Messageを "Welcome to Contoso University!" に変更します。

public ActionResult Index()
{
    ViewBag.Message = "Welcome to Contoso University";

    return View();
}

Ctrl キーを押しながら F5 キーを押してサイトを実行します。 メイン メニューが表示されたホーム ページが表示されます。

Contoso_University_home_page

データ モデルを作成する

次に、Contoso University アプリケーションのエンティティ クラスを作成します。 次の 3 つのエンティティから始めます。

Class_diagram

Student エンティティと Enrollment エンティティの間に一対多の関係があり、Course エンティティと Enrollment エンティティの間に一対多の関係があります。 言い換えると、1 人の学生をさまざまな講座に登録し、1 つの講座にたくさんの学生を登録できます。

次のセクションでは、エンティティごとにクラスを作成します。

注意

これらのエンティティ クラスの作成をすべて完了する前にプロジェクトをコンパイルしようとすると、コンパイラ エラーが発生します。

Student エンティティ

Student_entity

Models フォルダーでStudent.cs を作成し、既存のコードを次のコードに置き換えます。

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int StudentID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

StudentID プロパティは、このクラスに相当するデータベース テーブルの主キー列になります。 既定では、Entity Framework は、 または classnameID という名前IDのプロパティを主キーとして解釈します。

Enrollments プロパティはナビゲーション プロパティです。 ナビゲーション プロパティには、このエンティティに関連する他のエンティティが含まれます。 この場合、Enrollmentsエンティティの Student プロパティには、そのStudentエンティティにEnrollment関連するすべてのエンティティが保持されます。 言い換えると、データベース内の特定 Student の行に 2 つの関連 Enrollment 行 (外部キー列にその学生の主キー値を StudentID 含む行) がある場合、その Student エンティティの Enrollments ナビゲーション プロパティには、これら 2 つの Enrollment エンティティが含まれます。

ナビゲーション プロパティは、通常、遅延読み込みなどの特定の Entity Framework 機能を利用できるように としてvirtual定義されます。 (遅延読み込みについては、このシリーズの後半の 「関連データの読み取り 」チュートリアルで後ほど説明します。

ナビゲーション プロパティに複数のエンティティが含まれる場合 (多対多または一対多の関係で)、その型はリストにする必要があります。ICollection のように、エンティティを追加、削除、更新できるリストです。

登録エンティティ

Enrollment_entity

[Models] フォルダーで、Enrollment.cs を作成し、既存のコードを次のコードに変更します。

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        
        public virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }
}

Grade プロパティは 列挙型ですGrade の型宣言の後の疑問符は、Grade プロパティが nullable であることを示します。 null の成績が 0 の成績とは異なります。null は、成績が不明であるか、まだ割り当てられていないことを意味します。

StudentID プロパティは外部キーです。それに対応するナビゲーション プロパティは Student です。 Enrollment エンティティは 1 つの Student エンティティに関連付けられており、1 つの Student エンティティだけを保持できます (先に見た、複数の Enrollment エンティティを保持できる Student.Enrollments ナビゲーション プロパティとは異なります)。

CourseID プロパティは外部キーです。それに対応するナビゲーション プロパティは Course です。 Enrollment エンティティは 1 つの Course エンティティに関連付けられます。

Course エンティティ

Course_entity

Models フォルダーで 、Course.csを作成 、既存のコードを次のコードに置き換えます。

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

Enrollments プロパティはナビゲーション プロパティです。 1 つの Course エンティティにたくさんの Enrollment エンティティを関連付けることができます。

[DatabaseGenerated(DatabaseGeneratedOption) について詳しく説明します。次のチュートリアルの None)] 属性。 基本的に、この属性によって、講座の主キーをデータベースに生成させず、自分で入力できるようになります。

データベース コンテキストの作成

特定のデータ モデルの Entity Framework 機能を調整するメイン クラスは、データベース コンテキスト クラスです。 このクラスは、 System.Data.Entity.DbContext クラスから派生して作成します。 自分のコードでは、データ モデルに含めるエンティティを自分で指定します。 Entity Framework の特定の動作をカスタマイズすることもできます。 このプロジェクトでは、クラスに SchoolContext という名前が付けられています。

DAL という名前のフォルダーを作成します (データ アクセス層の場合)。 そのフォルダーに SchoolContext.cs という名前 新しいクラス ファイルを作成し、既存のコードを次のコードに置き換えます。

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ContosoUniversity.DAL
{
    public class SchoolContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}

このコードでは、各エンティティ セットの DbSet プロパティを作成します。 Entity Framework の用語では、 通常、エンティティ セット はデータベース テーブルに対応し、 エンティティ はテーブル内の行に対応します。

OnModelCreating メソッドの ステートメントはmodelBuilder.Conventions.Remove、テーブル名が複数形化されないようにします。 これを行わない場合、生成されたテーブルの名前 Studentsは 、、 Coursesおよび Enrollmentsになります。 代わりに、テーブル名は、、Course、および EnrollmentになりますStudent。 テーブル名を複数形にするかどうかについては、開発者の間で意見が分かれるでしょう。 このチュートリアルでは単数形を使用しますが、重要な点は、このコード行を含めたり省略したりして、任意のフォームを選択できることです。

SQL Server Express LocalDB

LocalDB は、オンデマンドで起動し、ユーザー モードで実行されるSQL Server Express データベース エンジンの軽量バージョンです。 LocalDB は、.mdf ファイルとしてデータベースを操作できる、SQL Server Expressの特別な実行モードで実行されます。 通常、LocalDB データベース ファイルは Web プロジェクトの App_Data フォルダーに保持されます。 SQL Server Expressのユーザー インスタンス機能を使用すると、.mdfファイルを操作することもできますが、ユーザー インスタンス機能は非推奨です。そのため、.mdf ファイルの操作には LocalDB をお勧めします。

通常、SQL Server Expressは運用 Web アプリケーションには使用されません。 特に LocalDB は、IIS で動作するように設計されていないため、Web アプリケーションでの運用環境での使用にはお勧めしません。

Visual Studio 2012 以降のバージョンでは、LocalDB は Visual Studio と共に既定でインストールされます。 Visual Studio 2010 以前のバージョンでは、Visual Studio では既定で SQL Server Express (LocalDB なし) がインストールされます。Visual Studio 2010 を使用している場合は、手動でインストールする必要があります。

このチュートリアルでは、LocalDB を使用して、 データベースを .mdfファイルとして App_Data フォルダーに格納できるようにします。 次の例に示すように、ルート Web.config ファイルをconnectionStrings開き、新しい接続文字列をコレクションに追加します。 (ルート プロジェクト フォルダー内の Web.config ファイルを必ず更新してください。また、更新する必要のない Web.config ファイルが Views サブフォルダーにあります)。

<add name="SchoolContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\ContosoUniversity.mdf" providerName="System.Data.SqlClient" />

既定では、Entity Framework は クラスと同じ という名前の接続文字列をDbContext検索します (SchoolContextこのプロジェクトの場合)。 追加した接続文字列は、App_Data フォルダーにあるContosoUniversity.mdf という名前の LocalDB データベースを指定します。 詳細については、「ASP.NET Web アプリケーションのSQL Server接続文字列」を参照してください。

実際には、接続文字列を指定する必要はありません。 接続文字列を指定しないと、Entity Framework によって作成されます。ただし、データベースがアプリの App_data フォルダーにない可能性があります。 データベースを作成する場所については、「 Code First to a New Database」を参照してください。

コレクションconnectionStringsには、メンバーシップ データベースに使用される という名前DefaultConnectionの接続文字列もあります。 このチュートリアルでは、メンバーシップ データベースを使用しません。 2 つの接続文字列の唯一の違いは、データベース名と名前の属性値です。

コードの最初の移行を設定して実行する

アプリケーションの開発を初めて開始すると、データ モデルは頻繁に変更され、モデルが変更されるたびにデータベースとの同期が失われます。 データ モデルを変更するたびにデータベースを自動的に削除して再作成するように Entity Framework を構成できます。 テスト データは簡単に再作成されるため、開発の早い段階では問題になりませんが、運用環境にデプロイした後は、通常、データベースを削除せずにデータベース スキーマを更新する必要があります。 移行機能を使用すると、Code First はデータベースを削除して再作成することなく、データベースを更新できます。 新しいプロジェクトの開発サイクルの早い段階で 、DropCreateDatabaseIfModelChanges を使用して、モデルが変更されるたびにデータベースを削除、再作成、再シードすることができます。 アプリケーションをデプロイする準備ができたら、移行アプローチに変換できます。 このチュートリアルでは、移行のみを使用します。 詳細については、「Code First Migrations移行のスクリーンキャスト シリーズ」を参照してください。

Code First Migrations の有効化

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

    Selecting_Package_Manager_Console

  2. プロンプトで、 PM> 次のコマンドを入力します。

    enable-migrations -contexttypename SchoolContext
    

    enable-migrations コマンド

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

    移行フォルダー

    クラスには Configuration 、データベースの Seed 作成時およびデータ モデル変更後に更新されるたびに呼び出されるメソッドが含まれます。

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.Models.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.Models.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 メソッドの目的は、アプリケーションがデータベースに初めてアクセスする前に、テーブルにデータを挿入できるようにすることです。

以前のバージョンの Code First では、移行がリリースされる前は、開発時にモデルが変更されるたびにデータベースを完全に削除して最初から再作成する必要があるため、メソッドでテスト データを挿入するのが一般的 Seed でした。 Code First Migrationsでは、データベースの変更後もテスト データが保持されるため、Seed メソッドにテスト データを含める必要はありません。 実際、Migrations を使用してデータベースを Seed 運用環境にデプロイする場合は、 メソッドをテスト データを挿入する必要はありません。これは、 メソッドが運用環境で実行されるためです Seed 。 その場合、メソッドを Seed データベースに挿入するには、運用環境に挿入するデータのみを使用します。 たとえば、アプリケーションが運用環境で使用可能になったときに、データベースに実際の部署名を Department テーブルに含めることができます。

このチュートリアルでは、デプロイに移行を使用しますが、多くのデータを Seed 手動で挿入しなくてもアプリケーションの機能がどのように機能するかを簡単に確認できるように、方法ではテスト データを挿入します。

  1. Configuration.cs ファイルの内容を次のコードに置き換えます。これにより、テスト データが新しいデータベースに読み込まれます。

    namespace ContosoUniversity.Migrations
    {
       using System;
       using System.Collections.Generic;
       using System.Data.Entity.Migrations;
       using System.Linq;
       using ContosoUniversity.Models;
    
       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").StudentID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").StudentID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
             foreach (Enrollment e in enrollments)
             {
                var enrollmentInDataBase = context.Enrollments.Where(
                    s =>
                         s.Student.StudentID == 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)
    

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

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

    メソッドの AddOrUpdate 詳細については、Julie Lerman のブログの 「EF 4.3 AddOrUpdate メソッドに注意 する」を参照してください。

    エンティティを追加 Enrollment するコードでは、 メソッドは AddOrUpdate 使用されません。 エンティティが既に存在するかどうかを確認し、存在しない場合はエンティティを挿入します。 この方法では、移行の実行時に登録グレードに加えた変更が保持されます。 このコードは List の各メンバーをEnrollmentループ処理し、登録がデータベースに見つからない場合は、登録をデータベースに追加します。 データベースを初めて更新すると、データベースは空になるため、各登録が追加されます。

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.StudentID == e.Student.StudentID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    

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

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

最初の移行を作成して実行する

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

    add-migration InitialCreate
    update-database
    

    [パッケージ マネージャー コンソール] ウィンドウを示すスクリーンショット。コマンドは、ハイフン移行アンダースコアを追加します。初期の作成と更新のハイフン データベースが強調表示されています。

    コマンドは add-migration 、データベースを作成するコードを含む [DateStamp]_InitialCreate.cs ファイルを Migrations フォルダーに追加します。 最初のパラメーター (InitialCreate) はファイル名に使用され、任意の名前を指定できます。通常は、移行で何が行われているかを要約した単語または語句を選択します。 たとえば、後で移行に "AddDepartmentTable" という名前を付ける可能性があります。

    初期移行を含む [移行] フォルダー

    クラスの InitialCreate メソッドはUp、データ モデル エンティティ セットに対応するデータベース テーブルを作成しDown、それらを削除します。 移行は、Up メソッドを呼び出して、移行のためのデータ モデルの変更を実装します。 更新をロールバックするためのコマンドを入力すると、移行が Down メソッドを呼び出します。 次のコードは、ファイルの内容を InitialCreate 示しています。

    namespace ContosoUniversity.Migrations
    {
        using System;
        using System.Data.Entity.Migrations;
        
        public partial class InitialCreate : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Student",
                    c => new
                        {
                            StudentID = c.Int(nullable: false, identity: true),
                            LastName = c.String(),
                            FirstMidName = c.String(),
                            EnrollmentDate = c.DateTime(nullable: false),
                        })
                    .PrimaryKey(t => t.StudentID);
                
                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.Course",
                    c => new
                        {
                            CourseID = c.Int(nullable: false),
                            Title = c.String(),
                            Credits = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.CourseID);
                
            }
            
            public override void Down()
            {
                DropIndex("dbo.Enrollment", new[] { "StudentID" });
                DropIndex("dbo.Enrollment", new[] { "CourseID" });
                DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
                DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
                DropTable("dbo.Course");
                DropTable("dbo.Enrollment");
                DropTable("dbo.Student");
            }
        }
    }
    

    コマンドは update-database 、 メソッドを Up 実行してデータベースを作成し、 メソッドを Seed 実行してデータベースを設定します。

これで、SQL Server データベースがデータ モデル用に作成されました。 データベースの名前は ContosoUniversity で、.mdf ファイルはプロジェクトの App_Data フォルダーにあります。これは、接続文字列で指定した名前であるためです。

Server エクスプローラー または SQL Server オブジェクト エクスプローラー (SSOX) を使用して、Visual Studio でデータベースを表示できます。 このチュートリアルでは、Server エクスプローラーを使用します。 Visual Studio Express 2012 for Web では、サーバー エクスプローラーデータベース エクスプローラーと呼ばれます。

  1. [表示] メニューの [サーバー エクスプローラー] をクリックします。

  2. [ 接続の追加] アイコンをクリックします。

    [データベース エクスプローラー] ウィンドウを示すスクリーンショット。[接続の追加] アイコンが強調表示されています。

  3. [データ ソースの選択] ダイアログボックスが表示されたら、[Microsoft SQL Server] をクリックし、[続行] をクリックします。

    [データ ソースの選択] ダイアログ ボックスを示すスクリーンショット。Microsoft S Q L Server データ ソースが選択されています。

  4. [接続の追加] ダイアログ ボックスで、サーバー名として「(localdb)\v11.0」と入力します。 [データベース名の選択または入力] で、[ContosoUniversity] を選択します。

    [接続の追加] ダイアログ ボックスを示すスクリーンショット。サンプルのサーバー名と Contoso University データベースが強調表示されています。

  5. [OK] をクリックします。

  6. [SchoolContext] を展開し、[テーブル] を展開します

    [サーバーのエクスプローラー] ページを示すスクリーンショット。[学校コンテキスト] タブと [テーブル] タブが展開されています。

  7. Student テーブルを右クリックし、[テーブル データの表示] をクリックすると、作成された列とテーブルに挿入された行が表示されます。

    Student テーブル

学生コントローラーとビューの作成

次の手順では、これらのテーブルのいずれかを操作できる ASP.NET MVC コントローラーとビューをアプリケーションに作成します。

  1. コントローラーをStudent作成するには、ソリューション エクスプローラーControllers フォルダーを右クリックし、[追加] を選択し、[コントローラー] をクリックします。 [ コントローラーの追加 ] ダイアログ ボックスで、次の選択を行い、[ 追加] をクリックします。

    • コントローラー名: StudentController

    • テンプレート: Entity Framework を使用した読み取り/書き込みアクションとビューを含む MVC コントローラー

    • モデル クラス: Student (ContosoUniversity.Models)。 (ドロップダウン リストにこのオプションが表示されない場合は、プロジェクトをビルドして、もう一度やり直してください。

    • データ コンテキスト クラス: SchoolContext (ContosoUniversity.Models)

    • ビュー: Razor (CSHTML)。 (既定値)。

      Add_Controller_dialog_box_for_Student_controller

  2. Visual Studio によって Controllers\StudentController.cs ファイルが 開きます。 データベース コンテキスト オブジェクトをインスタンス化するクラス変数が作成されていることがわかります。

    private SchoolContext db = new SchoolContext();
    

    アクション メソッドはIndex、データベース コンテキスト インスタンスの プロパティを読み取ることによってStudents、Students エンティティ セットから学生の一覧を取得します。

    public ViewResult Index()
    {
        return View(db.Students.ToList());
    }
    

    Student\Index.cshtml ビューでは、次の一覧がテーブルに表示されます。

    <table>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </th>
            <th></th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
                @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
            </td>
        </tr>
    }
    
  3. Ctrl キーを押しながら F5 キーを押してプロジェクトを実行します。

    [ 学生 ] タブをクリックして、メソッドが挿入したテスト データを Seed 表示します。

    [Student Index]\(学生インデックス\) ページ

規約

Entity Framework が完全なデータベースを作成できるようにするために記述する必要があったコードの量は、 慣例の使用や Entity Framework が行う前提のために最小限です。 その一部は既に示されています。

  • 複数形のエンティティ クラス名は、テーブル名として使用されます。
  • 列名には、エンティティ プロパティ名が使用されます。
  • 名前 ID または クラス名ID のエンティティ プロパティは、主キー プロパティとして認識されます。

規則をオーバーライドできることを確認しました (たとえば、テーブル名を複数形化しないように指定した場合)、規則とそのオーバーライド方法の詳細については、このシリーズの後半の「 より複雑なデータ モデルの作成 」チュートリアルを参照してください。 詳細については、「 Code First Conventions」を参照してください。

まとめ

これで、Entity Framework とSQL Server Expressを使用してデータを格納および表示する単純なアプリケーションが作成されました。 次のチュートリアルでは、基本的な CRUD (作成、読み取り、更新、削除) 操作を実行する方法について説明します。 フィードバックは、このページの下部に残すことができます。 チュートリアルのこの部分を気に入った方法と、それを改善する方法をお知らせください。

他の Entity Framework リソースへのリンクは、 ASP.NET データ アクセス コンテンツ マップにあります。