Entity Framework 4.0 Database First と ASP.NET 4 Web Forms の概要 - 第 7 部

著者: Tom Dykstra

Contoso University のサンプル Web アプリケーションでは、Entity Framework 4.0 と Visual Studio 2010 を使用して、ASP.NET Web Forms アプリケーションを作成する方法を示します。 このチュートリアル シリーズについては、このシリーズでの最初のチュートリアルを参照してください

ストアド プロシージャの使用

前のチュートリアルでは、Table-Per-Hierarchy 継承パターンを実装しました。 このチュートリアルでは、ストアド プロシージャを使用してデータベース アクセスをより詳細に制御する方法について説明します。

Entity Framework では、データベース アクセスにストアド プロシージャを使用するように指定できます。 どのエンティティ型でも、その型のエンティティの作成、更新、または削除に使用するストアド プロシージャを指定できます。 次に、データ モデルには、エンティティのセットの取得などのタスクを実行するために使用できるストアド プロシージャへの参照を追加できます。

ストアド プロシージャの使用は、データベース アクセスの一般的な要件です。 状況に応じて、データベース管理者が、セキュリティ上の理由から、すべてのデータベース アクセスがストアド プロシージャを経由することを必須にする場合があります。 また、データベースの更新時に Entity Framework が使用するプロセスの一部にビジネス ロジックを組み込む場合もあります。 たとえば、エンティティが削除されるたびに、それをアーカイブ データベースにコピーする場合があります。 または、行が更新されるたびに、変更を加えたユーザーを記録する行をログ テーブルに書き込むこともできます。 この種のタスクは、Entity Framework がエンティティを削除または更新するたびに呼び出されるストアド プロシージャで実行できます。

前のチュートリアルと同様に、新しいページは作成しません。 代わりに、既に作成した一部のページに対して Entity Framework がデータベースにアクセスする方法を変更します。

このチュートリアルでは、StudentInstructor のエンティティを挿入するためのストアド プロシージャをデータベースに作成します。 それらをデータ モデルに追加します。また、データベースに StudentInstructor のエンティティを追加する場合は、Entity Framework でそれらを使用する必要があることを指定します。 また、Course エンティティの取得に使用できるストアド プロシージャも作成します。

データベースでのストアド プロシージャの作成

(このチュートリアルでダウンロードできるプロジェクトの School.mdf ファイルを使用している場合は、ストアド プロシージャが既に存在するため、このセクションをスキップできます。)

サーバー エクスプローラーで、School.mdf を展開し、[ストアド プロシージャ] を右クリックして、[新しいストアド プロシージャの追加] を選びます。

image15

次の SQL ステートメントをコピーしてストアド プロシージャ ウィンドウに貼り付け、スケルトン ストアド プロシージャを置き換えます。

CREATE PROCEDURE [dbo].[InsertStudent]
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @EnrollmentDate datetime
    AS
    INSERT INTO dbo.Person (LastName, 
                FirstName, 
                EnrollmentDate)
    VALUES (@LastName, 
        @FirstName, 
        @EnrollmentDate);
    SELECT SCOPE_IDENTITY() as NewPersonID;

image14

Student エンティティには、PersonIDLastNameFirstNameEnrollmentDate という 4 つのプロパティがあります。 データベースは ID 値を自動的に生成し、ストアド プロシージャは他の 3 つのパラメーターを受け取ります。 ストアド プロシージャは新しい行のレコード キーの値を返すため、Entity Framework はメモリ内に保持するエンティティのバージョンでその値を追跡できます。

ストアド プロシージャ ウィンドウを保存して閉じます。

次の SQL ステートメントを使用して、同じ方法で InsertInstructor ストアド プロシージャを作成します。

CREATE PROCEDURE [dbo].[InsertInstructor]
        @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @HireDate datetime
    AS
    INSERT INTO dbo.Person (LastName, 
                FirstName, 
                HireDate)
    VALUES (@LastName, 
        @FirstName, 
        @HireDate);
    SELECT SCOPE_IDENTITY() as NewPersonID;

StudentInstructor のエンティティに対しても Update ストアド プロシージャを作成します (データベースには、InstructorStudent の両エンティティで機能する DeletePerson ストアド プロシージャが既に存在します)。

CREATE PROCEDURE [dbo].[UpdateStudent]
    @PersonID int,
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @EnrollmentDate datetime
    AS
    UPDATE Person SET LastName=@LastName, 
            FirstName=@FirstName,
            EnrollmentDate=@EnrollmentDate
    WHERE PersonID=@PersonID;
CREATE PROCEDURE [dbo].[UpdateInstructor]
    @PersonID int,
    @LastName nvarchar(50),
    @FirstName nvarchar(50),
    @HireDate datetime
    AS
    UPDATE Person SET LastName=@LastName, 
            FirstName=@FirstName,
            HireDate=@HireDate
    WHERE PersonID=@PersonID;

このチュートリアルでは、エンティティ型ごとに 3 つの関数 (insert、update、delete) をすべてマップします。 Entity Framework バージョン 4 では、これらの関数のうちの 1 つまたは 2 つだけをストアド プロシージャにマップし、その他をマップすることはできません。ただし、1 つの例外があります。update 関数をマップし、delete 関数をマップしない場合、エンティティを削除しようとしたときに Entity Framework から例外がスローされます。 Entity Framework バージョン 3.5 では、ストアド プロシージャのマッピングにこれほどの柔軟性はありませんでした。1 つの関数をマップした場合は、3 つすべてをマップする必要がありました。

データを更新するのではなく読み取るストアド プロシージャを作成するには、次の SQL ステートメントを使用して、すべての Course エンティティを選ぶものを作成します。

CREATE PROCEDURE [dbo].[GetCourses]
            AS
            SELECT CourseID, Title, Credits, DepartmentID FROM dbo.Course

データ モデルへのストアド プロシージャの追加

これでストアド プロシージャがデータベースに定義されましたが、Entity Framework で使用できるようにするには、データ モデルに追加する必要があります。 SchoolModel.edmx を開き、デザイン領域を右クリックして、[データベースからモデルを更新] を選びます。 [データベース オブジェクトの選択] ダイアログ ボックスの [追加] タブで、[ストアド プロシージャ] を展開し、新しく作成したストアド プロシージャと DeletePerson ストアド プロシージャを選んでから、[完了] をクリックします。

image20

ストアド プロシージャのマッピング

データ モデル デザイナーで Student エンティティを右クリックし、[ストアド プロシージャ マッピング] を選びます。

image21

[マッピングの詳細] ウィンドウが表示されます。ここで、Entity Framework がこの種類のエンティティの挿入、更新、削除に使用するストアド プロシージャを指定できます。

image22

Insert 関数を InsertStudent に設定します。 ウィンドウにはストアド プロシージャ パラメーターの一覧が表示されます。このそれぞれをエンティティ プロパティにマップする必要があります。 これらのうち 2 つは名前が同じであるため、自動的にマップされます。 FirstName というエンティティ プロパティがないため、使用できるエンティティ プロパティを表示するドロップダウン リストから手動で FirstMidName を選ぶ必要があります (これは、最初のチュートリアルで FirstName プロパティの名前を FirstMidName に変更したためです)。

image23

同じ [マッピングの詳細] ウィンドウで、Update 関数を UpdateStudent ストアド プロシージャにマップします (Insert ストアド プロシージャの場合と同様に、FirstName のパラメーター値として必ず FirstMidName を指定します)。また、Delete 関数を DeletePerson ストアド プロシージャにマップします。

image01

同じ手順に従って、講師用ストアド プロシージャの挿入、更新、削除のストアド プロシージャを Instructor エンティティにマップします。

image02

データを更新するのではなく読み取るストアド プロシージャの場合は、モデル ブラウザー ウィンドウを使用して、返されるエンティティ型にストアド プロシージャをマップします。 データ モデル デザイナーでデザイン領域を右クリックし、[モデル ブラウザー] を選びます。 SchoolModel.Store ノードを開いてから、ストアド プロシージャ ノードを開きます。 次に、GetCourses ストアド プロシージャを右クリックし、[関数インポートの追加] を選びます。

image24

[関数インポートの追加] ダイアログ ボックスの [コレクションを返す][エンティティ] を選び、返されるエンティティ型として Course を選びます。 終わったら [OK] をクリックします。 .edmx ファイルを保存して閉じます。

image25

挿入、更新、削除ストアド プロシージャの使用

データを挿入、更新、削除するストアド プロシージャは、データ モデルに追加して適切なエンティティにマップした後に、Entity Framework によって自動的に使用されます。 これで、StudentsAdd.aspx ページを実行できるようになります。新しい学生を作成するたびに、Entity Framework は InsertStudent ストアド プロシージャを使用して Student テーブルに新しい行を追加します。

image03

Students.aspx ページを実行すると、新しい学生が一覧に表示されます。

image04

名前を変更して update 関数が機能することを確認し、次に学生を削除して delete 関数が機能することを確認します。

image05

[ストアド プロシージャの選択] の使用

GetCourses などのストアド プロシージャは、Entity Framework によって自動実行されないため、それらを EntityDataSource コントロールで使用することはできません。 それらを使用するには、コードから呼び出します。

InstructorsCourses.aspx.cs ファイルを開きます。 PopulateDropDownLists メソッドは、LINQ-to-Entities クエリを使用してすべてのコース エンティティを取得します。これにより、一覧をループ処理して、講師が割り当てられているものと割り当てられていないものを判断できます。

var allCourses = (from c in context.Courses
                  select c).ToList();

これを次のコードに置き換えます。

var allCourses = context.GetCourses();

このページでは、GetCourses ストアド プロシージャを使用して、すべてのコースの一覧を取得します。 ページを実行して、以前と同じように機能することを確認します

(ストアド プロシージャによって取得されたエンティティのナビゲーション プロパティには、ObjectContext の既定の設定によっては、それらのエンティティに関連するデータが自動的に設定されない場合があります。詳細については、MSDN ライブラリの「関連オブジェクトの読み込み」を参照してください)。

次のチュートリアルでは、動的データ機能を使用して、データ形式と検証規則のプログラミングとテストを容易にする方法について説明します。 データ書式設定文字列やフィールドが必須かどうかなどの規則を Web ページごとに指定するのではなく、そのような規則をデータ モデルのメタデータで指定すると、すべてのページに自動的に適用されます。