チュートリアル: MVC 5 Web アプリの高度な EF シナリオについて説明します

前のチュートリアルでは、階層ごとのテーブルの継承を実装しました。 このチュートリアルでは、Entity Framework Code First を使用する web アプリケーションの開発の基本 ASP.NET 超える場合に注意するのに役立ついくつかのトピックについて説明します。 最初のいくつかのセクションでは、コードの手順と 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。 これがどのように機能するかを確認するには、コントローラーの メソッドでコードをDetailsDepartment変更します。

DepartmentController.cs の メソッドでDetails、 メソッド呼び出しをdb.Departments.FindAsyncdb.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 で、 メソッドの LINQ ステートメントを About 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());
}

[バージョン情報] ページを実行します。 以前と同じデータが表示されていることを確認します。

更新クエリの呼び出し

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

CourseController.cs で、 と HttpPostのメソッドをHttpGet追加UpdateCourseCreditsします。

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、テキスト ボックスに値が入力されます。 次に、コースを更新する SQL を実行し、影響を受ける行の数を変数のビューに ViewBag.RowsAffected 返します。 ビューがその変数の値を取得すると、テキスト ボックスと送信ボタンの代わりに更新された行数が表示されます。

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

Views\Course\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

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

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

生 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]}

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

コード行が強調表示されたコース コントローラーを示す 1 つのスクリーンショット。[テキスト ビジュアライザー] が開き、[値] フィールドに虫眼鏡が赤で囲まれている別のスクリーンショット。

次に、ドロップダウン リストを [コース インデックス] ページに追加して、ユーザーが特定の部門をフィルター処理できるようにします。 コースをタイトルで並べ替え、ナビゲーション プロパティの一括読み込みを 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 渡されるパラメーターは、値フィールド名、テキスト フィールド名、および選択した項目を指定します。

リポジトリの GetCourse メソッドの場合、コードはナビゲーション プロパティのフィルター式、並べ替え順序、および一括読み込みを 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にデータをJOIN読み込むDepartmentクエリになり、句が含まれていることをWHERE確認できます。

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

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

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

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

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

プロキシ クラス

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

プロキシ クラスの前

プロキシ クラスの後

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

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

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

詳細については、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 ダイアグラム

Entity Framework のソース コード

Entity Framework 6 のソース コードは 、GitHub で入手できます。 バグを報告したり、EF ソース コードに独自の機能強化を提供したりすることができます。

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

謝辞

  • Tom Dykstra は、このチュートリアルの元のバージョンを作成し、EF 5 更新プログラムを共同編集し、EF 6 更新プログラムを記述しました。 Tom は、Microsoft Web プラットフォームおよびツール コンテンツ チームのシニア プログラミング ライターです。
  • 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 検証エラーです。 メソッド のデバッグに関するヒントについては、「Entity Framework (EF) DB のシード処理と デバッグ Seed 」を参照してください。

HTTP 500.19 エラー

エラー メッセージ:

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

解決策

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

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

エラー メッセージ:

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

解決策

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

コードを取得する

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

その他のリソース

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

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 チュートリアル シリーズを参照してください。