デザイナーの CUD ストアド プロシージャ

このステップバイステップのチュートリアルでは、Entity Framework Designer (EF Designer) を使用して、エンティティ型の作成/挿入、更新、削除 (CUD) 操作をストアド プロシージャにマップする方法について説明します。  既定では、Entity Framework によって、CUD 操作の SQL ステートメントが自動的に生成されますが、これらの操作にストアド プロシージャをマップすることもできます。  

Code First では、ストアド プロシージャまたは関数へのマッピングはサポートされていません。 ただし、ストアド プロシージャまたは関数は、System.Data.Entity.DbSet.SqlQuery メソッドを使用して呼び出すことができます。 次に例を示します。

var query = context.Products.SqlQuery("EXECUTE [dbo].[GetAllProducts]");

CUD 操作をストアド プロシージャにマップする際の考慮事項

CUD 操作をストアド プロシージャにマップするときは、次の考慮事項が適用されます。

  • CUD 操作の 1 つをストアド プロシージャにマップする場合、すべての操作をマップします。 3 つすべてをマップしていない場合、マップされていない操作が実行されると失敗し、UpdateException がスローされます。
  • ストアド プロシージャのすべてのパラメーターをエンティティのプロパティにマップする必要があります。
  • サーバーによって、挿入された行の主キー値が生成された場合は、この値をエンティティのキー プロパティにマップする必要があります。 次の例では、InsertPerson ストアド プロシージャは、ストアド プロシージャの結果セットの一部として、新しく作成された主キーを返します。 主キーは、EF Designer の [<結果バインドの追加>] 機能を使用して、エンティティ キー (PersonID) にマップされます。
  • ストアド プロシージャの呼び出しは、概念モデルのエンティティと 1:1 でマップされます。 たとえば、概念モデルに継承階層を実装し、Parent (基本) エンティティと Child (派生) エンティティの CUD ストアド プロシージャをマップした場合、Child の変更を保存すると、Child のストアド プロシージャだけが呼び出され、Parent のストアド プロシージャの呼び出しはトリガーされません。

前提条件

このチュートリアルを完了するための要件を次に示します。

プロジェクトをセットアップする

  • Visual Studio 2012 を開きます。
  • [ファイル] -> [新規作成] -> [プロジェクト] の順に選択します。
  • 左ペインで [Visual C#] をクリックし、[コンソール] テンプレートを選択します。
  • 名前として「CUDSProcsSample」と入力します。
  • [OK] を選択します。

Create a Model (モデルの作成)

  • ソリューション エクスプローラーでプロジェクト名を右クリックし、[追加] -> [新しい項目] の順に選択します。

  • 左側のメニューから [データ] を選択し、[テンプレート] ペインの [ADO.NET Entity Data Model] を選択します。

  • ファイル名として「CUDSProcs.edmx」と入力し、[追加] をクリックします。

  • [モデルのコンテンツの選択] ダイアログ ボックスで、[データベースから生成] を選択し、[次へ] をクリックします。

  • [新しい接続] をクリックします。 [接続のプロパティ] ダイアログ ボックスで、サーバー名 (例: (localdb)\mssqllocaldb) を入力し、認証方法を選択します。データベース名として「School」と入力し、[OK] をクリックします。 指定したデータベース接続設定に従って、[データ接続の選択] ダイアログ ボックスが更新されます。

  • [データベース オブジェクトの選択] ダイアログ ボックスで、[テーブル] ノードの Person テーブルを選択します。

  • また、[ストアド プロシージャと関数] ノードで、DeletePersonInsertPersonUpdatePerson の各ストアド プロシージャを選択します。

  • Visual Studio 2012 以降では、EF Designer でストアド プロシージャの一括インポートがサポートされています。 [選択したストアド プロシージャと関数をエンティティ モデルにインポート] は既定でオンになっています。 この例では、エンティティ型を挿入、更新、削除するストアド プロシージャがあり、それらをインポートする必要はないため、このチェック ボックスをオフにします。

    Import S Procs

  • [完了] をクリックします。 モデルを編集するためのデザイン サーフェイスを提供する EF Designer が表示されます。

Person エンティティをストアド プロシージャにマップする

  • Person エンティティ型を右クリックし、[ストアド プロシージャ マッピング] を選択します。

  • [マッピングの詳細] ウィンドウにストアド プロシージャのマッピングが表示されます。

  • [<挿入関数の選択>] をクリックします。 このフィールドは、概念モデルのエンティティ型にマップできる、ストレージ モデル内のストアド プロシージャが表示されるドロップダウン リストです。 ドロップダウン リストから [InsertPerson] を選択します。

  • ストアド プロシージャのパラメーターとエンティティのプロパティとの既定のマッピングが表示されます。 矢印はマッピングの方向を表します (プロパティの値がストアド プロシージャのパラメーターに渡される)。

  • [<結果バインドの追加>] をクリックします。

  • NewPersonID」と入力します。これは、InsertPerson ストアド プロシージャから返されるパラメーターの名前です。 先頭または末尾のスペースは入力しないでください。

  • Enter キーを押します。

  • 既定では、NewPersonID はエンティティ キー PersonID にマップされます。 矢印はマッピングの方向を表します (結果列の値がプロパティに渡される)。

    Mapping Details

  • [<更新関数の選択>] をクリックし、表示されるドロップダウン リストから [UpdatePerson] を選択します。

  • ストアド プロシージャのパラメーターとエンティティのプロパティとの既定のマッピングが表示されます。

  • [<削除関数の選択>] をクリックし、表示されるドロップダウン リストから [DeletePerson] を選択します。

  • ストアド プロシージャのパラメーターとエンティティのプロパティとの既定のマッピングが表示されます。

これで、Person エンティティ型の挿入、更新、削除の操作がストアド プロシージャにマップされました。

ストアド プロシージャを使用してエンティティを更新または削除するときにコンカレンシー チェックを有効にする場合は、次のいずれかの方法を使用します。

  • ストアド プロシージャから影響を受けた行の数を返すには、OUTPUT パラメーターを使用し、パラメーター名の横の [処理行数パラメーター] チェック ボックスをオンにします。 操作が呼び出されたときに返される値が 0 の場合、OptimisticConcurrencyException がスローされます。
  • コンカレンシー チェックに使用するプロパティの横の [元の値を使用する] チェック ボックスをオンにします。 更新が試行され、データベースにデータを書き戻すときに、データベースから読み取られた元のプロパティ値が使用されます。 その値がデータベースの値と一致しない場合、OptimisticConcurrencyException がスローされます。

モデルを使用する

Main メソッドが定義されている Program.cs ファイルを開きます。 Main 関数に次のコードを追加します。

このコードでは、新しい Person オブジェクトを作成し、オブジェクトを更新して、最後にオブジェクトを削除します。

    using (var context = new SchoolEntities())
    {
        var newInstructor = new Person
        {
            FirstName = "Robyn",
            LastName = "Martin",
            HireDate = DateTime.Now,
            Discriminator = "Instructor"
        }

        // Add the new object to the context.
        context.People.Add(newInstructor);

        Console.WriteLine("Added {0} {1} to the context.",
            newInstructor.FirstName, newInstructor.LastName);

        Console.WriteLine("Before SaveChanges, the PersonID is: {0}",
            newInstructor.PersonID);

        // SaveChanges will call the InsertPerson sproc.  
        // The PersonID property will be assigned the value
        // returned by the sproc.
        context.SaveChanges();

        Console.WriteLine("After SaveChanges, the PersonID is: {0}",
            newInstructor.PersonID);

        // Modify the object and call SaveChanges.
        // This time, the UpdatePerson will be called.
        newInstructor.FirstName = "Rachel";
        context.SaveChanges();

        // Remove the object from the context and call SaveChanges.
        // The DeletePerson sproc will be called.
        context.People.Remove(newInstructor);
        context.SaveChanges();

        Person deletedInstructor = context.People.
            Where(p => p.PersonID == newInstructor.PersonID).
            FirstOrDefault();

        if (deletedInstructor == null)
            Console.WriteLine("A person with PersonID {0} was deleted.",
                newInstructor.PersonID);
    }
  • アプリケーションをコンパイルして実行します。 このプログラムの出力は次のようになります。*

Note

PersonID はサーバーによって自動生成されるため、通常、異なる数値が表示されます。*

Added Robyn Martin to the context.
Before SaveChanges, the PersonID is: 0
After SaveChanges, the PersonID is: 51
A person with PersonID 51 was deleted.

Ultimate バージョンの Visual Studio を使用している場合は、デバッガーで IntelliTrace を使用して、実行される SQL ステートメントを確認できます。

Debug With Intellitrace