チュートリアル: ASP.NET MVC で Entity Framework を使用して CRUD 機能を実装する

前のチュートリアルでは、Entity Framework (EF) 6 と LocalDB を使用してデータを格納および表示する MVC アプリケーションSQL Server作成しました。 このチュートリアルでは、MVC スキャフォールディングによってコントローラーとビューで自動的に作成される作成、読み取り、更新、削除 (CRUD) コードを確認してカスタマイズします。

Note

コントローラーとデータ アクセス層の間に抽象化レイヤーを作成するためにリポジトリ パターンを実装することは、よく行われることです。 これらのチュートリアルをシンプルに保ち、EF 6 自体の使用方法を教えることに重点を置くために、リポジトリは使用しません。 リポジトリを実装する方法については、「 ASP.NET データ アクセス コンテンツ マップ」を参照してください。

作成する Web ページの例を次に示します。

学生の詳細ページのスクリーンショット。

学生の作成ページのスクリーンショット。

学生の削除ページのスクリーンショット。

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

  • [詳細の作成] ページ
  • Create ページを更新する
  • HttpPost Edit メソッドを更新する
  • [削除] ページを更新する
  • データベース接続を閉じる
  • トランザクションを処理する

前提条件

[詳細の作成] ページ

Students Index ページのスキャフォールディングされたコードは、そのプロパティがコレクションを Enrollments 保持しているため、プロパティを省略しました。 ページでは Details 、コレクションの内容を HTML テーブルに表示します。

Controllers\StudentController.cs では、ビューのDetailsアクション メソッドは Find メソッドを使用して 1 つのStudentエンティティを取得します。

public ActionResult Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Find(id);
    if (student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

キー値は パラメーターとして id メソッドに渡され、[インデックス] ページの [詳細] ハイパーリンクのルート データから取得されます。

ヒント: ルート データ

ルート データは、ルーティング テーブルで指定された URL セグメントでモデル バインダーが見つけたデータです。 たとえば、既定のルートでは、および id セグメントをcontrolleraction指定します。

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

次の URL では、既定のルートは として actioncontrollerIndex として、1 は としてidマップInstructorされます。これらはルート データ値です。

http://localhost:1230/Instructor/Index/1?courseID=2021

?courseID=2021 はクエリ文字列値です。 をクエリ文字列値として渡 id すと、モデル バインダーも機能します。

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

URL は Razor ビューのステートメントによって ActionLink 作成されます。 次のコードでは、 パラメーターは id 既定のルートと一致するため id 、ルート データに追加されます。

@Html.ActionLink("Select", "Index", new { id = item.PersonID  })

次のコードでは、 courseID は既定のルートのパラメーターと一致しないため、クエリ文字列として追加されます。

@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })

[詳細] ページを作成するには

  1. Views\Student\Details.cshtml を開きます

    次の例に示すように、各フィールドはヘルパーを使用して DisplayFor 表示されます。

    <dt>
        @Html.DisplayNameFor(model => model.LastName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.LastName)
    </dd>
    
  2. フィールドの EnrollmentDate 後と終了 </dl> タグの直前に、次の例に示すように、強調表示されたコードを追加して登録の一覧を表示します。

    <dt>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.EnrollmentDate)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Enrollments)
            </dt>
            <dd>
                <table class="table">
                    <tr>
                        <th>Course Title</th>
                        <th>Grade</th>
                    </tr>
                    @foreach (var item in Model.Enrollments)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.Course.Title)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Grade)
                            </td>
                        </tr>
                    }
                </table>
            </dd>
        </dl>
    </div>
    <p>
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
        @Html.ActionLink("Back to List", "Index")
    </p>
    

    コードを貼り付けた後にコードのインデントが間違っている場合は、CtrlK キー、Ctrl+Dキー+を押して書式を設定します。

    このコードは、Enrollments ナビゲーション プロパティ内のエンティティをループ処理します。 プロパティのエンティティごとに Enrollment 、コースのタイトルと成績が表示されます。 コースタイトルは、エンティティのCourseナビゲーション プロパティEnrollmentsCourse格納されているエンティティから取得されます。 このデータはすべて、必要なときにデータベースから自動的に取得されます。 言い換えると、ここでは遅延読み込みを使用しています。 ナビゲーション プロパティに一Courses括読み込みを指定しなかったため、学生を取得したのと同じクエリで登録が取得されませんでした。 代わりに、ナビゲーション プロパティに初めてアクセス Enrollments しようとすると、新しいクエリがデータベースに送信され、データが取得されます。 遅延読み込みと一括読み込みの詳細については、このシリーズの後半の 「関連データの読み取り 」チュートリアルを参照してください。

  3. プログラムを開始して [詳細] ページを開きます (CtrlF5キー+を押し、[学生] タブを選択し、Alexander Carson の [詳細] リンクをクリックします。 (Ctrl キー+を押すとDetails.cshtml ファイルが開いている間に F5、HTTP 400 エラーが発生します。これは、Visual Studio が [詳細] ページを実行しようとしますが、表示する学生を指定するリンクから到達できなかったためです。その場合は、URL から "Student/Details" を削除してやり直すか、ブラウザーを閉じてプロジェクトを右クリックし、[ブラウザーでビュー表示>] をクリックします)。

    選択した学生のコースと成績の一覧が表示されます。

  4. ブラウザーを閉じます。

[作成] ページを更新する

  1. Controllers\StudentController.cs で、action メソッドをHttpPostAttributeCreate次のコードに置き換えます。 このコードでは、ブロックをtry-catch追加し、スキャフォールディング されたメソッドの BindAttribute 属性から を削除IDします。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
    {
        try
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
        catch (DataException /* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
        }
        return View(student);
    }
    

    このコードは、 Student ASP.NET MVC モデル バインダーによって作成されたエンティティを Students エンティティ セットに追加し、変更をデータベースに保存します。 モデル バインダー とは、フォームによって送信されたデータを簡単に操作できるようにする ASP.NET MVC 機能を指します。モデル バインダーは、ポストされたフォーム値を CLR 型に変換し、パラメーターでアクション メソッドに渡します。 この場合、モデル バインダーは、コレクションのプロパティ値を Student 使用してエンティティを Form インスタンス化します。

    Bind 属性から削除したID理由は、行が挿入されたときに自動的に設定SQL Server主キー値であるためIDです。 ユーザーからの入力では、値は ID 設定されません。

    セキュリティ警告 - 属性はValidateAntiForgeryToken、クロスサイト リクエスト フォージェリ攻撃を防ぐのに役立ちます。 ビューには対応する Html.AntiForgeryToken() ステートメントが必要です。これについては後で説明します。

    属性は Bind 、作成シナリオでの 過剰転記 から保護する 1 つの方法です。 たとえば、エンティティに Student 、この Web ページで Secret 設定したくないプロパティが含まれているとします。

    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public string Secret { get; set; }
    
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
    

    Web ページにフィールドがない Secret 場合でも、ハッカーは fiddler などのツールを使用したり、JavaScript を記述してフォーム値を Secret 投稿したりできます。 モデル バインダーがインスタンスの BindAttribute 作成時 Student に使用するフィールドを属性で制限しない場合 モデル バインダーはその Secret フォーム値を取得し、それを使用してエンティティ インスタンスを Student 作成します。 その場合、Secret フォーム フィールドに対してハッカーが指定した値はすべて、データベースで更新されます。 次の図は、fiddler ツールが投稿されたフォーム値に Secret フィールド (値 "OverPost" を含む) を追加する方法を示しています。

    [Composer] タブを示すスクリーンショット。右上隅の [実行] は赤で囲まれています。右下隅のシークレットと等しい [ポストオーバー] は赤で囲まれています。

    値 "OverPost" は挿入される行の Secret プロパティに正常に追加されますが、Web ページがそのプロパティを設定できることは意図したものではありません。

    属性と共に パラメーターを Include 使用して、フィールドを Bind 明示的に一覧表示することをお勧めします。 パラメーターを使用 Exclude して、除外するフィールドをブロックすることもできます。 その理由 Include は、エンティティに新しいプロパティを追加すると、新しいフィールドがリストによって Exclude 自動的に保護されないためです。

    最初にデータベースからエンティティを読み取り、次に を呼び出 TryUpdateModelして、明示的に許可されたプロパティ リストを渡すことで、編集シナリオでの過剰ポストを防ぐことができます。 これは、これらのチュートリアルで使用されるメソッドです。

    多くの開発者が推奨する過剰投稿を防ぐ別の方法は、モデル バインドを使用したエンティティ クラスではなく、ビュー モデルを使用することです。 更新するプロパティのみをビュー モデルに含めます。 MVC モデル バインダーが完了したら、必要に応じて AutoMapper などのツールを使用して、ビュー モデルのプロパティをエンティティ インスタンスにコピーします。 db を使用します。エンティティ インスタンスのエントリで状態を変更なしに設定し、Property("PropertyName") を設定します。ビュー モデルに含まれる各エンティティ プロパティで IsModified を true に設定します。 この方法は、編集シナリオと作成シナリオの両方で利用できます。

    属性以外の Bind ブロックは、 try-catch スキャフォールディングされたコードに対して行った唯一の変更です。 変更を保存するときに、DataException から派生した例外がキャッチされた場合は、汎用的なエラー メッセージが表示されます。 DataException 例外は、プログラミング エラーではなくアプリケーション外の何かが原因で発生する場合があるので、再試行することをお勧めします。 このサンプルでは実装されていませんが、運用品質のアプリケーションでは例外をログに記録します。 詳細については、「Monitoring and Telemetry (Building Real-World Cloud Apps with Azure)」(監視とテレメトリ (Azure での実際のクラウド アプリの構築)) の「Log for insight」(洞察のためのログ) セクションをご覧ください。

    Views\Student\Create.cshtml のコードは Details.cshtml で見たものと似ていますがEditorFor、 と ValidationMessageFor ヘルパーは ではなくDisplayFor各フィールドで使用されます。 関連するコードを次に示します。

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
    </div>
    

    Create.cshtml には も含まれています@Html.AntiForgeryToken()。これは、クロスサイト要求フォージェリ攻撃を防ぐのに役立つコントローラーの 属性と連携ValidateAntiForgeryTokenします。

    Create.cshtml では変更は必要ありません。

  2. プログラムを起動し、[ 学生 ] タブを選択し、[ 新規作成] をクリックしてページを実行します。

  3. 名前と無効な日付を入力し、[ 作成 ] をクリックしてエラー メッセージを表示します。

    これは、既定で取得するサーバー側の検証です。 後のチュートリアルでは、クライアント側検証用のコードを生成する属性を追加する方法について説明します。 次の強調表示されたコードは、Create メソッドのモデル検証チェックを示しています。

    if (ModelState.IsValid)
    {
        db.Students.Add(student);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    
  4. 日付を有効な値に変更し、 [Create] をクリックして、新しい学生が [Index] ページに表示されることを確認します。

  5. ブラウザーを閉じます。

Update HttpPost Edit メソッド

  1. action メソッドを HttpPostAttributeEdit 次のコードに置き換えます。

    [HttpPost, ActionName("Edit")]
    [ValidateAntiForgeryToken]
    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var studentToUpdate = db.Students.Find(id);
        if (TryUpdateModel(studentToUpdate, "",
           new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
        {
            try
            {
                db.SaveChanges();
    
                return RedirectToAction("Index");
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
            }
        }
        return View(studentToUpdate);
    }
    

    Note

    Controllers\StudentController.cs では、 HttpGet Edit メソッド (属性のないHttpPostメソッド) は、 メソッドをFind使用して選択したStudentエンティティをDetails取得します。これは、 メソッドで確認したとおりです。 このメソッドを変更する必要はありません。

    これらの変更では、 オーバーポストを防ぐためのセキュリティのベスト プラクティスが実装されています。スキャフォールディングによって属性が生成 Bind され、モデル バインダーによって作成されたエンティティが Modified フラグを持つエンティティ セットに追加されました。 このコードは、パラメーターに Bind リストされていないフィールド内の既存のデータが属性によってクリアされるため、 Include 推奨されなくなりました。 今後、MVC コントローラー スキャフォールディングが更新され、Edit メソッドの属性が生成 Bind されなくなります。

    新しいコードは、既存のエンティティを読み取り、 を呼び出 TryUpdateModel して、投稿されたフォーム データのユーザー入力からフィールドを更新します。 Entity Framework の自動変更追跡では、エンティティに EntityState.Modified フラグが設定されます。 SaveChanges メソッドが呼び出されると、 フラグによって Modified Entity Framework によって SQL ステートメントが作成され、データベース行が更新されます。 コンカレンシーの競合 は無視され、ユーザーが変更しなかった列を含め、データベース行のすべての列が更新されます。 (後のチュートリアルでは、コンカレンシーの競合を処理する方法を示します。データベース内の個々のフィールドのみを更新する場合は、エンティティを EntityState.Unchanged に設定し、個々のフィールドを EntityState.Modified に設定できます)。

    オーバーポストを防ぐために、[編集] ページで更新可能にするフィールドがパラメーターに TryUpdateModel 一覧表示されます。 現在、他に保護しているフィールドはありませんが、モデル バインダーでバインドしたいフィールドをリストに入れておくと、後でデータ モデルにフィールドを追加した場合に、ここでフィールドを明示的に追加するまで、自動的にフィールドを保護できます。

    これらの変更の結果、HttpPost Edit メソッドのメソッド シグネチャは HttpGet 編集メソッドと同じです。そのため、EditPost メソッドの名前を変更しました。

    ヒント

    エンティティの状態と Attach メソッドと SaveChanges メソッド

    データベース コンテキストは、メモリ内のエンティティがデータベースの対応する行と同期しているかどうかを追跡しており、この情報により、SaveChanges メソッドを呼び出したときの処理が決まります。 たとえば、新しいエンティティを Add メソッドに渡すと、そのエンティティの状態は に Added設定されます。 次に、 SaveChanges メソッドを呼び出すと、データベース コンテキストによって SQL INSERT コマンドが発行されます。

    エンティティは、次のいずれかの 状態になります。

    • Added. エンティティはまだデータベースに存在しません。 メソッドは SaveChanges ステートメントを発行する INSERT 必要があります。
    • Unchanged. SaveChanges メソッドはこのエンティティに対し何も行う必要はありません。 データベースからエンティティを読み取ると、エンティティはこの状態で開始します。
    • Modified. エンティティのプロパティ値の一部またはすべてが変更されています。 メソッドは SaveChanges ステートメントを発行する UPDATE 必要があります。
    • Deleted. エンティティには削除のマークが付けられています。 メソッドは SaveChanges ステートメントを発行する DELETE 必要があります。
    • Detached. エンティティはデータベース コンテキストによって追跡されていません。

    デスクトップ アプリケーションにおいて、通常、状態の変更は自動的に設定されます。 デスクトップの種類のアプリケーションでは、エンティティを読み取り、そのプロパティ値の一部を変更します。 そのエンティティの状態は自動的に Modified に変更されます。 次に、 を呼び出 SaveChangesすと、変更した実際のプロパティのみを更新する SQL UPDATE ステートメントが Entity Framework によって生成されます。

    Web アプリの切断された性質では、この連続したシーケンスは許可されません。 エンティティを読み取る DbContext は、ページのレンダリング後に破棄されます。 HttpPostEditアクション メソッドが呼び出されると、新しい要求が行われ、DbContext の新しいインスタンスが作成されるため、エンティティの状態を手動で に設定するModified.必要があります。 を呼び出SaveChangesすと、コンテキストで変更したプロパティを知る方法がないため、Entity Framework によってデータベース行のすべての列が更新されます。

    ユーザーが実際に変更したフィールドのみを SQL Update ステートメントで更新する場合は、元の値 (非表示フィールドなど) を何らかの方法で保存して、メソッドの呼び出し時 HttpPostEdit に使用できるようにします。 次に、元の値を使用してエンティティを作成 Student し、その元のバージョンのエンティティで メソッドを呼び出 Attach し、エンティティの値を新しい値に更新してから、 を呼び出します SaveChanges. 。詳細については、「 Entity states and SaveChanges andLocal Data」を参照してください。

    Views\Student\Edit.cshtml の HTML コードと Razor コードは、Create.cshtml で見たものと似ていますが、変更は必要ありません。

  2. プログラムを起動し、[ 学生 ] タブを選択し、[ 編集 ] ハイパーリンクをクリックしてページを実行します。

  3. データをいくつか変更し、 [Save] をクリックします。 [インデックス] ページに変更されたデータが表示されます。

  4. ブラウザーを閉じます。

[削除] ページを更新する

Controllers\StudentController.cs のメソッドのテンプレート コードHttpGetAttributeDeleteでは、 メソッドと Edit メソッドで確認したように、 メソッドを使用Findして選択したStudentエンティティをDetails取得します。 ただし、SaveChanges の呼び出しが失敗したときのカスタム エラー メッセージを実装するには、何らかの機能とその対応するビューをこのメソッドに追加します。

更新および作成操作で見たように、削除操作にも 2 つのアクション メソッドが必要です。 GET 要求に応答して呼び出されるメソッドには、削除操作を承認または取り消す機会をユーザーに提供するビューが表示されます。 ユーザーが操作を承認すると、POST 要求が作成されます。 その場合、 HttpPostDelete メソッドが呼び出され、そのメソッドは実際に削除操作を実行します。

データベースの更新時に発生するHttpPostAttributeDelete可能性のあるエラーを処理するブロックを メソッドに追加try-catchします。 エラーが発生した場合、メソッドは HttpPostAttributeDelete メソッドを HttpGetAttributeDelete 呼び出し、エラーが発生したことを示すパラメーターを渡します。 次に、 メソッドは HttpGetAttributeDelete 確認ページとエラー メッセージを再表示し、ユーザーにキャンセルまたは再試行を行う機会を提供します。

  1. action メソッドを HttpGetAttributeDelete 、エラー報告を管理する次のコードに置き換えます。

    public ActionResult Delete(int? id, bool? saveChangesError=false)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        if (saveChangesError.GetValueOrDefault())
        {
            ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
        }
        Student student = db.Students.Find(id);
        if (student == null)
        {
            return HttpNotFound();
        }
        return View(student);
    }
    

    このコードは、変更の保存に失敗した後にメソッドが呼び出されたかどうかを示す 省略可能なパラメーター を受け取ります。 このパラメーターは、 false メソッドが以前の HttpGetDelete エラーなしで呼び出された場合です。 データベース更新エラーに応答して メソッドによって HttpPostDelete 呼び出されると、 パラメーターが になり true 、エラー メッセージがビューに渡されます。

  2. HttpPostAttributeDeleteアクション メソッド (という名前DeleteConfirmed) を、実際の削除操作を実行し、データベース更新エラーをキャッチする次のコードに置き換えます。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(int id)
    {
        try
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
        }
        catch (DataException/* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            return RedirectToAction("Delete", new { id = id, saveChangesError = true });
        }
        return RedirectToAction("Index");
    }
    

    このコードは、選択したエンティティを取得し、 Remove メソッドを呼び出してエンティティの状態を に Deleted設定します。 SaveChanges が呼び出された場合、SQL の DELETE コマンドが生成されます。 また、アクション メソッドの名前を DeleteConfirmed から Delete に変更しています。 メソッドに一意のシグネチャを HttpPostDelete 与える メソッド DeleteConfirmed という名前の HttpPost スキャフォールディング されたコード。 (CLR では、異なるメソッド パラメーターを持つオーバーロードされたメソッドが必要です)。シグネチャが一意になったので、MVC 規則に従い、 メソッドと HttpGet delete メソッドに同じ名前をHttpPost使用できます。

    大量のアプリケーションでのパフォーマンスの向上が優先される場合は、 メソッドと Remove メソッドを呼び出すFindコード行を次のコードに置き換えることで、不要な SQL クエリを回避して行を取得できます。

    Student studentToDelete = new Student() { ID = id };
    db.Entry(studentToDelete).State = EntityState.Deleted;
    

    このコードでは、 Student 主キー値のみを使用してエンティティをインスタンス化し、エンティティの状態を に Deleted設定します。 エンティティを削除するために Entity Framework に必要なものは主キーの値だけです

    前に示したように、 HttpGetDelete メソッドはデータを削除しません。 GET 要求に応答して削除操作を実行すると (つまり、編集操作、作成操作、またはデータを変更するその他の操作を実行する)、セキュリティ 上のリスクが生じます。 詳細については、「 ASP.NET MVC ヒント #46 - Stephen Walther のブログにセキュリティ ホールが作成されるため、リンクの削除を使用しないでください 」を参照してください。

  3. Views\Student\Delete.cshtml で、次の例に示すように、見出しと見出しのh3h2にエラー メッセージを追加します。

    <h2>Delete</h2>
    <p class="error">@ViewBag.ErrorMessage</p>
    <h3>Are you sure you want to delete this?</h3>
    
  4. プログラムを起動し、[ 学生 ] タブを選択し、[削除] ハイパーリンクをクリックして、ページを実行 します

  5. [ 削除 しますか?] というページで [ 削除] を選択します。

    [インデックス] ページが表示され、学生は削除されません。 ( 同時実行のチュートリアルでは、動作中のエラー処理コードの例が表示されます)。

データベース接続を閉じる

データベース接続を閉じて、保持しているリソースをできるだけ早く解放するには、コンテキスト インスタンスが完了したら破棄します。 そのため、スキャフォールディングされたコードは、次の例に示すように、StudentController.cs のクラスのStudentController末尾に Dispose メソッドを提供します。

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

基底 Controller クラスは既に インターフェイスを IDisposable 実装しているため、このコードは単純に メソッドにオーバーライドを追加して Dispose(bool) 、コンテキスト インスタンスを明示的に破棄します。

トランザクションを処理する

既定では、Entity Framework はトランザクションを暗黙的に実装します。 複数の行またはテーブルに変更を加えて から を呼び出す SaveChangesシナリオでは、Entity Framework によって、すべての変更が成功するか、すべて失敗するかを自動的に確認します。 一部の変更が完了した後でエラーが発生した場合、それらの変更は自動的にロールバックされます。 より多くの制御が必要なシナリオ (たとえば、Entity Framework の外部で実行される操作をトランザクションに含める場合) については、「 トランザクションの操作」を参照してください。

コードを取得する

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

その他のリソース

これで、エンティティに対 Student して単純な CRUD 操作を実行するページの完全なセットが作成されました。 MVC ヘルパーを使用して、データ フィールドの UI 要素を生成しました。 MVC ヘルパーの詳細については、「 HTML ヘルパーを使用したフォームのレンダリング 」を参照してください (この記事は MVC 3 用ですが、MVC 5 にはまだ関連しています)。

他の EF 6 リソースへのリンクは、「 ASP.NET データ アクセス - 推奨リソース」にあります

次の手順

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

  • [詳細] ページを作成しました
  • Create ページを更新した
  • HttpPost Edit メソッドを更新しました
  • Delete ページを更新した
  • データベース接続を閉じた
  • 処理されたトランザクション

次の記事に進み、プロジェクトに並べ替え、フィルター処理、ページングを追加する方法について説明します。