このチュートリアルでは、Entity Framework Designer (EF Designer) を使用して概念モデルに階層ごとのテーブル (TPH) 継承を実装する方法について説明します。 TPH 継承では、1 つのデータベース テーブルを使用して、継承階層内のすべてのエンティティ型のデータを保持します。
このチュートリアルでは、Person テーブルを、Person (基本型)、Student (Person から派生)、Instructor (Person から派生) の 3 つのエンティティ型にマップします。 データベース (Database First) から概念モデルを作成し、EF デザイナーを使用して TPH 継承を実装するようにモデルを変更します。
Model First を使用して TPH 継承にマップすることはできますが、複雑な独自のデータベース生成ワークフローを記述する必要があります。 次に、EF デザイナーの データベース生成ワークフロー プロパティにこのワークフローを割り当てます。 コード ファーストを使用する方が簡単な方法です。
その他の継承オプション
Table-per-Type (TPT) は、データベース内の個別のテーブルが継承に参加するエンティティにマップされる別の種類の継承です。 型ごとのテーブルの継承を EF デザイナーでマップする方法については、「 EF Designer TPT 継承」を参照してください。
Table-per-Concrete Type Inheritance (TPC) および混合継承モデルは Entity Framework ランタイムでサポートされますが、EF デザイナーではサポートされていません。 TPC または混合継承を使用する場合は、Code First を使用するか、EDMX ファイルを手動で編集するかの 2 つのオプションがあります。 EDMX ファイルの操作を選択した場合、マッピングの詳細ウィンドウは "セーフ モード" になり、デザイナーを使用してマッピングを変更することはできません。
前提条件
このチュートリアルを完了するための要件を次に示します。
- 最新バージョンの Visual Studio。
- 「School」サンプル データベース。
プロジェクトを設定する
- Visual Studio 2012 を開きます。
- [ファイル] -> [新規作成] -> [プロジェクト] の順に選択します。
- 左ペインで [Visual C#] をクリックし、[コンソール] テンプレートを選択します。
- 名前として 「TPHDBFirstSample 」と入力します。
- [OK] を選択.
Create a Model (モデルの作成)
- ソリューション エクスプローラーでプロジェクト名を右クリックし、[追加] -> [新しい項目] を選択します。
- 左側のメニューから [データ] を選択し、[テンプレート] ペインの [ADO.NET Entity Data Model] を選択します。
- ファイル名として 「TPHModel.edmx 」と入力し、[ 追加] をクリックします。
- [モデルのコンテンツの選択] ダイアログ ボックスで、[データベースから生成] を選択し、[次へ] をクリックします。
- [新しい接続] をクリックします。 [接続のプロパティ] ダイアログ ボックスで、サーバー名 (例: (localdb)\mssqllocaldb) を入力し、認証方法を選択します。データベース名として「School」と入力し、[OK] をクリックします。 指定したデータベース接続設定に従って、[データ接続の選択] ダイアログ ボックスが更新されます。
- [データベース オブジェクトの選択] ダイアログ ボックスの [テーブル] ノードで、 Person テーブルを選択します。
- [完了] をクリックします。
モデルを編集するためのデザイン 画面を提供するエンティティ デザイナーが表示されます。 [データベース オブジェクトの選択] ダイアログ ボックスで選択したすべてのオブジェクトがモデルに追加されます。
これは、 Person テーブルがデータベース内でどのように表示されるかを示します。
階層ごとのテーブル (Table-per-Hierarchy) の継承を実装する
Person テーブルには識別子列があり、"Student" と "Instructor" の 2 つの値のいずれかを指定できます。 値に応じて、 Person テーブルは Student エンティティまたは Instructor エンティティにマップされます。 Person テーブルには、HireDate と EnrollmentDate という 2 つの列もあります。この列は null 許容である必要があります。これは、1 人のユーザーが同時に学生とインストラクターになることができないためです (このチュートリアルでは少なくともできません)。
新しいエンティティを追加する
- 新しいエンティティを追加します。 これを行うには、Entity Framework デザイナーのデザイン サーフェイスの空の領域を右クリックし、[ Add->Entity] を選択します。
- エンティティ名に「Instructor」と入力し、[基本] 型のドロップダウン リストから [Person] を選択します。
- OK をクリックします。
- 別の新しいエンティティを追加します。 エンティティ名に「Student」と入力し、[基本] タイプのドロップダウン リストから [Person] を選択します。
2 つの新しいエンティティ型がデザイン サーフェイスに追加されました。 矢印は、新しいエンティティ型から Person エンティティ型を指しています。これは、 Person が新しいエンティティ型の基本型であることを示します。
- Person エンティティの HireDate プロパティを右クリックします。 [切り取り] を選択します (または、Ctrl-X キーを使用します)。
- Instructor エンティティを右クリックし、[貼り付け] を選択します (または、Ctrl-V キーを使用します)。
- HireDate プロパティを右クリックし、[プロパティ] を選択します。
- プロパティウィンドウで、ヌル許容プロパティをfalseに設定します。
- Person エンティティの EnrollmentDate プロパティを右クリックします。 [切り取り] を選択します (または、Ctrl-X キーを使用します)。
- Student エンティティを右クリックし、[貼り付け] を選択します (または、Ctrl-V キーを使用します)。
- EnrollmentDate プロパティを選択し、Nullable プロパティを false に設定します。
- Person エンティティの種類を選択します。 [ プロパティ ] ウィンドウで、 Abstract プロパティを true に設定 します。
- Person から識別子プロパティを削除します。 削除する必要がある理由については、次のセクションで説明します。
エンティティをマップする
Instructor を右クリックし、[テーブル マッピング] を選択します。[Mapping Details]\(マッピングの詳細\) ウィンドウで Instructor エンティティが選択されています。
[<] ウィンドウで>テーブルまたはビューの追加をクリックします。 <テーブルまたはビューの追加> フィールドは、選択したエンティティをマップできるテーブルまたはビューのドロップダウン リストになります。
ドロップダウン リストから [ ユーザー ] を選択します。
[ マッピングの詳細] ウィンドウは、既定の列マッピングと、条件を追加するためのオプションで更新されます。
<条件の追加>をクリックします。 <条件の追加>フィールドは、条件を設定できる列のドロップダウン リストになります。
ドロップダウン リストから [ 識別子 ] を選択します。
[マッピングの詳細] ウィンドウの [演算子] 列で、ドロップダウン リストから =を選択します。
[ 値/プロパティ ] 列に「 Instructor」と入力します。 最終的な結果はこのようになります。
Student エンティティ型に対してこれらの手順を繰り返しますが、条件を Student 値と同じにします。
識別子プロパティを削除する理由は、テーブル列を複数回マップできないためです。 この列は条件付きマッピングに使用されるため、プロパティ マッピングにも使用できません。 条件で Is Null または Is Not Null 比較が使用されている場合は、両方に使用できる唯一の方法です。
階層ごとのテーブルの継承が実装されました。
モデルを使用する
Main メソッドが定義されている Program.cs ファイルを開きます。 次のコードを Main 関数に貼り付けます。 このコードでは、3 つのクエリが実行されます。 最初のクエリでは、すべての Person オブジェクトが返されます。 2 番目のクエリでは、 OfType メソッドを使用して Instructor オブジェクトを返します。 3 番目のクエリでは、 OfType メソッドを使用して Student オブジェクトを返します。
using (var context = new SchoolEntities())
{
Console.WriteLine("All people:");
foreach (var person in context.People)
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
Console.WriteLine("Instructors only: ");
foreach (var person in context.People.OfType<Instructor>())
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
Console.WriteLine("Students only: ");
foreach (var person in context.People.OfType<Student>())
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
}
.NET