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

作成者: Tom Dykstra

Note

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

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

Code First

Entity Framework でデータを操作するには、 Database FirstModel FirstCode 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 に関するメモについては、シリーズの最後のチュートリアルを参照してください。

チュートリアルの元のバージョン

チュートリアルの元のバージョンは、 EF 4.1/ MVC 3 電子書籍で入手できます。

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 つの講座にたくさんの学生を登録できます。

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

Note

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

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になります。 代わりに、テーブル名は Student、、 Course、および Enrollmentになります。 テーブル名を複数形にするかどうかについては、開発者の間で意見が分かれるでしょう。 このチュートリアルでは単数形を使用しますが、重要な点は、このコード行を含めたり省略したりすることで、任意のフォームを選択できることです。

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 以前のバージョンでは、SQL Server Express (LocalDB なし) は Visual Studio で既定でインストールされます。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 つの接続文字列の唯一の違いは、データベース名と name 属性値です。

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

アプリケーションの開発を初めて開始すると、データ モデルは頻繁に変更され、モデルが変更されるたびにデータベースとの同期が取れなくなります。 データ モデルを変更するたびにデータベースを自動的に削除して再作成するように 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 ファイルを配置します。このファイルを編集して移行を構成できます。

    Migrations フォルダー

    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 使用可能になったときに、データベースに実際の部署名をテーブルに含める場合があります。

このチュートリアルでは、デプロイに Migrations を使用しますが、多くのデータを 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 フォルダーにあります。これは接続文字列で指定した名前であるためです。

サーバー エクスプローラーまたは SQL Server オブジェクト エクスプローラー (SSOX) のいずれかを使用して、Visual Studio でデータベースを表示できます。 このチュートリアルでは、 サーバー エクスプローラーを使用します。 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 データ アクセス コンテンツ マップにあります。