次の方法で共有


チュートリアル: MVC 5 Web アプリの高度な EF シナリオについて学習する

前のチュートリアルでは、Table-Per-Hierarchy 継承を実装しました。 このチュートリアルでは、Entity Framework Core First を使用するより高度な ASP.NET Web アプリケーションを開発する際に、注意すべきいくつかのトピックを紹介します。 最初のいくつかのセクションには、コードと Visual Studio を使用してタスクを完了する手順が記載されています。以降のセクションでは、いくつかのトピックを紹介し、簡単な概要を紹介した後、詳細についてのリソースへのリンクを示します。

これらのトピックのほとんどでは、既に作成したページを操作します。 生 SQL を使用して一括更新を行うには、データベース内のすべてのコースのクレジット数を更新する新しいページを作成します。

Update_Course_Credits_initial_page

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

  • 生 SQL クエリを実行する
  • 追跡なしのクエリの実行
  • データベースに送信された SQL クエリの調査

以下についても学習します。

  • 抽象化レイヤーの作成
  • プロキシ クラス
  • 変更の自動検出
  • 自動検証
  • Entity Framework Power Tools
  • Entity Framework のソース コード

前提条件

生 SQL クエリを実行する

Entity Framework Code First API には、SQL コマンドをデータベースに直接渡せるようにするメソッドが含まれています。 次のようなオプションがあります。

  • エンティティ型を返すクエリに対して DbSet.SqlQuery メソッドを使用します。 返されたオブジェクトは、DbSet オブジェクトで想定されている型である必要があります。また、追跡をオフにしない限り、オブジェクトはデータベース コンテキストによって自動的に追跡されます。 (AsNoTracking メソッドについては次のセクションを参照してください。)
  • エンティティではない型を返すクエリには、Database.SqlQuery メソッドを使用します。 このメソッドを使用してエンティティ型を取得する場合でも、返されるデータはデータベース コンテキストによって追跡されません。
  • クエリ以外のコマンドには、Database.ExecuteSqlCommand を使用します。

Entity Framework を使用する利点の 1 つは、データを格納する特定のメソッドにコードを過度に接近させなくてもよい点です。 SQL クエリとコマンドが生成されるため、自分でこれらを記述する必要がなくなります。 ただし、手動で作成した特定の SQL クエリを実行する必要がある場合は、例外的なシナリオがあります。これらのメソッドを使用すると、このような例外を処理できます。

Web アプリケーションで SQL コマンドを実行する場合は常に、SQL インジェクション攻撃から自身のサイトを保護する対策を講じる必要があります。 これを行う 1 つの方法として、パラメーター化されたクエリを使用して、Web ページによって送信された文字列が SQL コマンドとして解釈できないことを確認します。 このチュートリアルでは、ユーザー入力をクエリに統合するときに、パラメーター化されたクエリを使用します。

エンティティを返すクエリの呼び出し

DbSet<TEntity> クラスは、TEntity 型のエンティティを返すクエリの実行に使用できるメソッドを提供します。 このしくみを確認するため、Department コントローラーの Details メソッド内のコードを変更します。

DepartmentController.csDetails メソッドで、次の強調表示されたコードに示されているように、db.Departments.FindAsync メソッド呼び出しを db.Departments.SqlQuery メソッド呼び出しに置き換えます。

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    // Commenting out original code to show how to use a raw SQL query.
    //Department department = await db.Departments.FindAsync(id);

    // Create and execute raw SQL query.
    string query = "SELECT * FROM Department WHERE DepartmentID = @p0";
    Department department = await db.Departments.SqlQuery(query, id).SingleOrDefaultAsync();
    
    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

新しいコードが正しく動作することを確認するには、 [Departments](部門) タブを選択し、いずれかの部門の [Details](詳細) を選択します。 すべてのデータが期待どおりに表示されていることを確認します。

他の種類のオブジェクトを返すクエリの呼び出し

以前に、登録日ごとの学生数を示す About ページ用に、学生の統計グリッドを作成しました。 HomeController.cs でこれを行うコードでは、LINQ を使用します。

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

LINQ を使用するのではなく、SQL でこのデータを直接取得するコードを記述するとします。 そのためには、エンティティ オブジェクト以外のものを返すクエリを実行する必要があります。つまり、Database.SqlQuery メソッドを使用する必要があります。

HomeController.cs で、次の強調表示されたコードに示すように、About メソッド内の LINQ ステートメントを SQL ステートメントに置き換えます。

public ActionResult About()
{
    // Commenting out LINQ to show how to do the same thing in SQL.
    //IQueryable<EnrollmentDateGroup> = from student in db.Students
    //           group student by student.EnrollmentDate into dateGroup
    //           select new EnrollmentDateGroup()
    //           {
    //               EnrollmentDate = dateGroup.Key,
    //               StudentCount = dateGroup.Count()
    //           };

    // SQL version of the above LINQ code.
    string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
        + "FROM Person "
        + "WHERE Discriminator = 'Student' "
        + "GROUP BY EnrollmentDate";
    IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

    return View(data.ToList());
}

[About] ページを実行します。 以前と同じデータが表示されたことを確認します。

更新クエリの呼び出し

Contoso University の管理者が、すべてのコースの単位数を変更するなどの、データベースでの一括変更をする機能を求めているとします。 大学に多くのコースがある場合は、それらすべてをエンティティとして取得し、それらを個別に変更するのは非効率的です。 このセクションでは、すべてのコースの単位数を変更する係数をユーザーが指定できるようにする Web ページを実装し、SQL UPDATE ステートメントを実行することによって変更を行います。

CourseController.cs で、HttpGetHttpPostUpdateCourseCredits メソッドを追加します。

public ActionResult UpdateCourseCredits()
{
    return View();
}

[HttpPost]
public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = db.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
    }
    return View();
}

コントローラーが HttpGet 要求を処理するときは、ViewBag.RowsAffected 変数には何も返されず、ビューには空のテキスト ボックスと、[送信] ボタンが表示されます。

[更新] ボタンをクリックすると、HttpPost メソッドが呼び出され、multiplier がテキスト ボックスに入力した値になります。 このコードは次に、コースを更新し、影響を受けた行の数を ViewBag.RowsAffected 変数のビューに返す SQL を実行します。 ビューがその変数の値を取得すると、テキスト ボックスと送信ボタンの代わりに更新された行数が表示されます。

CourseController.cs で、UpdateCourseCredits メソッドのうちひとつを右クリックし、[ビューの追加] をクリックします。 [ビューの追加] ダイアログが表示されます。 既定値のままにし、次に [追加] を選択します。

Views/Courses/UpdateCourseCredits.cshtml で、テンプレート コードを次のコードに置き換えます。

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

[Courses](コース) タブを選択してから、ブラウザーのアドレス バーで URL の末尾に "/UpdateCourseCredits" を追加して (例: http://localhost:50205/Course/UpdateCourseCredits)、UpdateCourseCredits メソッドを実行します。 テキスト ボックスに数値を入力します。

Update_Course_Credits_initial_page_with_2_entered

[更新] をクリックします。 影響を受けた行の数が表示されます。

[リストに戻る] をクリックして、単位数が変更されたコースの一覧を表示します。

SQL クエリの詳細については、MSDN の「生 SQL クエリ」を参照してください。

追跡なしのクエリ

データベース コンテキストは、テーブルの行を取得してそれらを表すエンティティ オブジェクトを作成するとき、既定では、メモリ内のエンティティがデータベース内のデータと同期されているかどうかを追跡します。 メモリ内のデータはキャッシュとして機能し、エンティティを更新するときに使われます。 Web アプリケーションでは、一般にコンテキスト インスタンスの存続期間は短く (要求ごとに新しいインスタンスが作成されて破棄されます)、通常、エンティティを読み取るコンテキストはエンティティが再び使われる前に破棄されるので、多くの場合、このようなキャッシュは必要ありません。

AsNoTracking メソッドを使用することで、メモリ内のエンティティ オブジェクトの追跡を無効にすることができます。 追跡を無効にした方がよい一般的なシナリオを以下に示します。

  • クエリは、追跡をオフにするとパフォーマンスが著しく向上する可能性がある大量のデータを取得します。
  • エンティティを更新するためにアタッチする必要があるが、それより前に別の目的で同じエンティティを取得してある場合。 エンティティはデータベース コンテキストによって既に追跡されているため、変更するエンティティをアタッチできません。 このような状況に対処する方法の 1 つは、前のクエリで AsNoTracking オプションを使用することです。

AsNoTracking メソッドの使用方法を示す例については、このチュートリアルの以前のバージョンを参照してください。 このバージョンのチュートリアルでは、Edit メソッドでモデル バインダーによって作成されたエンティティに Modified フラグが設定されていないため、AsNoTracking は必要ありません。

データベースに送信される SQL を調べる

データベースに送信される実際の SQL クエリを確認できると役立つ場合があります。 前のチュートリアルでは、インターセプター コードでこれを行う方法を確認しました。ここでは、インターセプター コードを記述せずにそれを行ういくつかの方法を確認します。 これを試すには、まずシンプルなクエリを見てから、一括読み込み、フィルター処理、並べ替えなどのオプションを追加するとどうなるかを確認します。

Controllers/CourseController で、一括読み込みを一時的に停止するために、Index メソッドを次のコードに置き換えます。

public ActionResult Index()
{
    var courses = db.Courses;
    var sql = courses.ToString();
    return View(courses.ToList());
}

次に、return ステートメントにブレークポイントを設定します (その行にカーソルを置いて F9 キー)。 F5 を押してプロジェクトをデバッグ モードで実行し、[コース インデックス] ページを選択します。 コードがブレークポイントに到達したら、sql 変数を調べます。 SQL Server に送信されたクエリが表示されます。 これはシンプルな Select ステートメントです。

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

虫眼鏡をクリックすると、テキスト ビジュアライザーにクエリが表示されます。

One screenshot that shows the Course Controller with a line of code highlighted. Another screenshot that shows the Text Visualizer open and a magnifying glass is circled in red in the Value field.

次に、ユーザーが特定の部門をフィルター処理できるように、ドロップダウン リストを [コース インデックス] ページに追加します。 タイトルでコースを並べ替え、Department ナビゲーション プロパティに一括読み込みを指定します。

CourseController.cs で、Index メソッドを次のコードに置き換えます。

public ActionResult Index(int? SelectedDepartment)
{
    var departments = db.Departments.OrderBy(q => q.Name).ToList();
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);
    int departmentID = SelectedDepartment.GetValueOrDefault();

    IQueryable<Course> courses = db.Courses
        .Where(c => !SelectedDepartment.HasValue || c.DepartmentID == departmentID)
        .OrderBy(d => d.CourseID)
        .Include(d => d.Department);
    var sql = courses.ToString();
    return View(courses.ToList());
}

return ステートメントにブレークポイントを復元します。

このメソッドは、SelectedDepartment パラメーター内のドロップダウン リストの選択された値を受け取ります。 何も選択しない場合、このパラメーターは null になります。

すべての部門を含む SelectList コレクションが、ドロップダウン リストのビューに渡されます。 SelectList コンストラクターに渡されるパラメーターは、値フィールド名、テキスト フィールド名、および選択した項目を指定します。

Course リポジトリの Get メソッドでは、コードは Department ナビゲーション プロパティのフィルター式、並べ替え順序、および一括読み込みを指定します。 フィルター式は、ドロップダウン リストで何も選択されていない場合 (つまり SelectedDepartment が null の場合)、常に true が返されます。

Views\Course\Index.cshtml で、最初の table タグの直前に次のコードを追加して、ドロップダウン リストと送信ボタンを作成します。

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

ブレークポイントを設定したまま、[コース インデックス] ページを実行します。 ページがブラウザーに表示されるように、コードがブレークポイントにヒットするまで続行します。 ドロップダウン リストから部署を選択し、[フィルター] をクリックします。

今回は、最初のブレークポイントがドロップダウン リストの部署クエリ用になります。 次にコードがブレークポイントに到達したら、それをスキップして query 変数を表示し、Course クエリがどのように表示されるかを確認します。 次のように表示されます。

SELECT 
    [Project1].[CourseID] AS [CourseID], 
    [Project1].[Title] AS [Title], 
    [Project1].[Credits] AS [Credits], 
    [Project1].[DepartmentID] AS [DepartmentID], 
    [Project1].[DepartmentID1] AS [DepartmentID1], 
    [Project1].[Name] AS [Name], 
    [Project1].[Budget] AS [Budget], 
    [Project1].[StartDate] AS [StartDate], 
    [Project1].[InstructorID] AS [InstructorID], 
    [Project1].[RowVersion] AS [RowVersion]
    FROM ( SELECT 
        [Extent1].[CourseID] AS [CourseID], 
        [Extent1].[Title] AS [Title], 
        [Extent1].[Credits] AS [Credits], 
        [Extent1].[DepartmentID] AS [DepartmentID], 
        [Extent2].[DepartmentID] AS [DepartmentID1], 
        [Extent2].[Name] AS [Name], 
        [Extent2].[Budget] AS [Budget], 
        [Extent2].[StartDate] AS [StartDate], 
        [Extent2].[InstructorID] AS [InstructorID], 
        [Extent2].[RowVersion] AS [RowVersion]
        FROM  [dbo].[Course] AS [Extent1]
        INNER JOIN [dbo].[Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
        WHERE @p__linq__0 IS NULL OR [Extent1].[DepartmentID] = @p__linq__1
    )  AS [Project1]
    ORDER BY [Project1].[CourseID] ASC

クエリが Course データと共に Department データを読み込む JOIN クエリになり、WHERE 句が含まれていることを確認できます。

var sql = courses.ToString() 行を削除します。

抽象化レイヤーを作成する

多くの開発者は、Entity Framework で動作するコードをラップするラッパーとして、Repository パターンと Unit of Work パターンを実装するためのコードを記述します。 これらのパターンは、アプリケーションのデータ アクセス層とビジネス ロジック層の間に抽象化レイヤーを作成するためのものです。 これらのパターンを実装すると、データ ストアの変更からアプリケーションを隔離でき、自動化された単体テストやテスト駆動開発 (TDD) を円滑化できます。 ただし、次の複数の理由により、追加のコードを記述してこれらのパターンを実装することが、EF を使用するアプリケーションにとって最善の選択肢ではない場合もあります。

  • EF コンテキスト クラス自体が、コードをデータ ストア固有のコードから隔離します。
  • EF コンテキスト クラスは、EF を使用して行っているデータベースの更新の unit-of-work クラスとして動作できます。
  • Entity Framework 6 で導入された機能により、リポジトリ コードを記述せずに TDD を簡単に実装できます。

Repository パターンと Unit of Work パターンを実装する方法の詳細については、このチュートリアル シリーズの Entity Framework 5 バージョンを参照してください。 Entity Framework 6 で TDD を実装する方法については、次のリソースを参照してください。

プロキシ クラス

Entity Framework によってエンティティ インスタンスが作成される際 (クエリを実行する場合など)、そのインスタンスは多くの場合、エンティティのプロキシとして機能する、動的に生成された派生型のインスタンスとして作成されます。 たとえば、次の 2 つのデバッガー イメージを参照してください。 最初の画像では、エンティティをインスタンス化した直後に、student 変数が予期される Student 型であることがわかります。 2 番目の画像では、EF を使用してデータベースから学生エンティティを読み取った後、プロキシ クラスが表示されます。

Before proxy class

After proxy class

このプロキシ クラスは、プロパティがアクセスされたときにアクションを自動的に実行するフックを挿入するために、エンティティの一部の仮想プロパティをオーバーライドします。 このメカニズムが使用される関数の 1 つは遅延読み込みです。

ほとんどの場合、プロキシのこの使用に注意する必要はありませんが、例外があります。

  • 一部のシナリオでは、場合により、Entity Framework でプロキシ インスタンスが作成されないようにする必要があります。 たとえば、エンティティをシリアル化する場合、通常はプロキシ クラスではなく POCO クラスが必要です。 シリアル化の問題を回避する 1 つの方法は、「Entity Framework での Web API の使用」チュートリアルで示されているように、エンティティ オブジェクトではなくデータ転送オブジェクト (DTO) をシリアル化することです。 もう 1 つの方法は、プロキシ作成の無効化です。
  • new 演算子を使用してエンティティ クラスをインスタンス化すると、プロキシ インスタンスは取得されません。 つまり、遅延読み込みや自動変更追跡などの機能は取得しません。 これは通常問題ありません。データベースにない新しいエンティティを作成するため、通常は遅延読み込みを必要としません。また、エンティティを明示的に Added としてマークする場合は、通常、変更の追跡は必要ありません。 ただし、遅延読み込みが必要で、変更の追跡も必要な場合は、DbSet クラスの Create メソッドを使用してプロキシを持つ新しいエンティティ インスタンスを作成できます。
  • プロキシ型から実際のエンティティ型を取得したい場合があります。 ObjectContext クラスの GetObjectType メソッドを使用して、プロキシ型インスタンスの実際のエンティティ型を取得できます。

詳細については、MSDN の「プロキシの使用」を参照してください。

変更の自動検出

Entity Framework では、エンティティの現在の値と元の値を比較して、エンティティがどのように変更されたか (およびそれによって、どの更新プログラムをデータベースに送信する必要があるか) を判断します。 元の値は、エンティティが照会されるかアタッチされるときに格納されます。 変更の自動検出を行うメソッドには、次のようなものがあります。

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

多数のエンティティを追跡していて、これらのいずれかのメソッドをループ内で何度も呼び出す場合、AutoDetectChangesEnabled プロパティを使用して変更の自動検出を一時的にオフにすると、パフォーマンスが大幅に向上する場合があります。 詳細については、MSDN の「変更の自動検出」を参照してください。

自動検証

SaveChanges メソッドを呼び出すと、既定では、Entity Framework は、データベースを更新する前に、変更されたすべてのエンティティのすべてのプロパティのデータを検証します。 多数のエンティティを更新し、既にデータを検証している場合、この作業は不要であり、検証を一時的に無効にすることで、変更を保存するプロセスの時間を短縮できます。 これを行うには、ValidateOnSaveEnabled プロパティを 使用します。 詳細については、MSDN の検証に関するページを参照してください。

Entity Framework Power Tools

Entity Framework Power Tools は、これらのチュートリアルで示すデータ モデル図を作成するために使用された Visual Studio アドインです。 また、既存のデータベースのテーブルに基づいてエンティティ クラスを生成するなど、他の機能を実行して、Code First でデータベースを使用することもできます。 ツールをインストールすると、コンテキスト メニューにいくつかの追加オプションが表示されます。 たとえば、ソリューション エクスプローラーでコンテキスト クラスを右クリックすると、Entity Framework オプションが表示されます。 これで図を生成できます。 Code First を使用している場合、図のデータ モデルを変更することはできませんが、わかりやすくするための移動は行えます。

EF diagram

Entity Framework のソース コード

Entity Framework 6 のソース コードは GitHub で入手できます。 バグの報告や、EF ソース コードへの独自の拡張機能の提供が行えます。

ソース コードはオープンですが、Entity Framework は Microsoft 製品として完全にサポートされています。 Microsoft Entity Framework チームは、各リリースの品質を保証するため、受け入れる投稿を管理し、すべてのコード変更をテストしています。

謝辞

  • Tom Dykstra は、このチュートリアルの元のバージョンを記述し、EF 5 更新プログラムを共同作成し、EF 6 更新プログラムを記述しました。 Tom は、Microsoft Web Platform and Tools コンテンツ チームのシニア プログラミング ライターです。
  • Rick Anderson (twitter @RickAndMSFT) は、EF 5 と MVC 4 のチュートリアルを更新する作業のほとんどを行い、EF 6 更新プログラムを共同編集しました。 Rick は、Azure と MVC に重点を置く Microsoft のシニア プログラミング ライターです。
  • Rowan Miller と Entity Framework チームの他のメンバーが、コード レビューを支援し、EF 5 および EF 6 のチュートリアルの更新中に発生した移行に関する多くの問題のデバッグに協力しました。

一般的なエラーのトラブルシューティング

コピーを作成またはシャドウできない

エラー メッセージ:

そのファイルが既に存在する場合、'<filename>' を作成/シャドウ コピーできません。

解決策

数秒待ってから、ページを更新します。

Update-Database が認識されない

エラー メッセージ (PMC の Update-Database コマンドから):

"Update-Database" という語が、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。 名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してください。

解決策

Visual Studio を終了します。 プロジェクトを再度開き、もう一度やり直してください。

検証に失敗しました

エラー メッセージ (PMC の Update-Database コマンドから):

1 つ以上のエンティティの検証に失敗しました。 詳細については、'EntityValidationErrors' プロパティを参照してください。

解決策

この問題の原因の 1 つは、Seed メソッドの実行時の検証エラーです。 Seed メソッドのデバッグに関するヒントについては、「Entity Framework (EF) DB のシード処理とデバッグ」を 参照してください。

HTTP 500.19 エラー

エラー メッセージ:

HTTP エラー 500.19 - 内部サーバー エラー - ページに関連する構成データが無効であるため、要求されたページにアクセスできません。

解決策

このエラーの要因の 1 つは、ソリューションの複数のコピーがあり、それぞれが同じポート番号を使用していることです。 通常、この問題を解決するには、Visual Studio のすべてのインスタンスを終了してから、作業中のプロジェクトを再起動します。 それでも問題が解決しない場合は、ポート番号を変更してみてください。 プロジェクト ファイルを右クリックし、[プロパティ] をクリックします。 [Web] タブを選択し、[プロジェクトの URL] テキスト ボックスでポート番号を変更します。

SQL Server インスタンスの位置を特定しているときのエラー

エラー メッセージ:

SQL Server への接続を確立しているときに、ネットワーク関連またはインスタンス固有のエラーが発生しました。 サーバーが見つからないかアクセスできません。 インスタンス名が正しいこと、および SQL Server がリモート接続を許可するように構成されていることを確認してください。 (プロバイダー:SQL Network Interfaces、エラー:26 - 指定されたサーバーまたはインスタンスの位置を特定しているときにエラーが発生しました)

解決策

接続文字列を確認します。 データベースを手動で削除した場合は、構築文字列内のデータベース名を変更します。

コードを取得する

完成したプロジェクトのダウンロード

その他のリソース

Entity Framework を使用してデータを操作する方法の詳細については、MSDN の EF ドキュメント ページと「ASP.NET データ アクセス - 推奨リソース」を参照してください。

Web アプリケーションの構築後にデプロイする方法の詳細については、MSDN ライブラリの「ASP NET Web デプロイ - 推奨リソース」を参照 してください。

認証や承認など、MVC に関連するその他のトピックについては、「ASP.NET MVC - 推奨リソース」を参照してください。

次のステップ

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

  • 生 SQL クエリを実行した
  • 追跡なしのクエリを実行済み
  • データベースに送信された SQL クエリを調査済み

また、次についても説明しました。

  • 抽象化レイヤーの作成
  • プロキシ クラス
  • 変更の自動検出
  • 自動検証
  • Entity Framework Power Tools
  • Entity Framework のソース コード

これで、ASP.NET MVC アプリケーションでの Entity Framework の使用に関する一連のチュートリアルは終了です。 EF Database First については、DB First チュートリアル シリーズを参照してください。