チュートリアル : Table-Per-Type 継承のマッピング
このトピックでは、Entity Data Model (EDM) で概念モデルを変更することによって Table-Per-Type 継承を実装する方法について説明します。Table-Per-Type 継承は、データベース内の別個のテーブルを使用して、非継承プロパティと継承階層のそれぞれの型のキー プロパティのデータを維持します。EDM での継承の実装の詳細については、「継承 (EDM)」を参照してください。
このチュートリアルでは、CourseManager アプリケーションで使用する EDM を変更することによって、Table-Per-Type 継承を実装します (詳細については、このトピックの「前提条件」を参照してください)。
CourseManager アプリケーションでは、Course、OnlineCourse、および OnsiteCourse エンティティ型は同じ名前のテーブルにマップされます。OnlineCourse および OnsiteCourse エンティティ型は、2 つのコース型に固有の情報を格納し、共通のキーを共有しているため、Course エンティティ型から継承するよう変更できます。以下の手順は、この場合の Table-Per-Type 継承を実装する方法をまとめたものです (このトピックの後半では、これらの手順について詳しく説明します)。
OnlineCourse エンティティ型と Course エンティティ型の間のアソシエーションを削除します。OnsiteCourse エンティティ型と Course エンティティ型の間のアソシエーションを削除します。これらのアソシエーションは、継承階層の実装によって置き換えられます。
OnlineCourse および OnsiteCourse エンティティ型から CourseID キー プロパティを削除します。このプロパティは、Course エンティティ型から継承されます。
Course エンティティ型を OnlineCourse および OnsiteCourse エンティティ型の基本データ型として設定します。
Course エンティティ型を抽象型にします。
OnlineCourse および OnsiteCourse エンティティ型の継承された CourseID プロパティを適切な列にマップします。
前提条件
このチュートリアルを完了するには、最初に CourseManager アプリケーションを構築する必要があります。詳細と手順については、「Entity Framework クイック スタート」を参照してください。Table-Per-Type 継承を実装して、CourseManager アプリケーションで使用する EDM を変更します。選択した部門のオンライン コースとオンサイト コースを別々に表示するには、アプリケーションの機能を拡張します。
[!メモ]
このドキュメントのチュートリアルのトピックの多くは CourseManager アプリケーションを開始点としているため、元の CourseManager コードを編集するのではなく、このチュートリアル用に CourseManager アプリケーションのコピーを使用することをお勧めします。
このチュートリアルでは、Visual Studio、.NET Framework、および Visual C# または Visual Basic のプログラミングの基本的なスキルがある読者を想定しています。
Table-Per-Type 継承の実装
この手順では、SchoolModel EDM の概念モデルを変更することによって Table-Per-Type 継承を実装します。
Table-Per-Type 継承を実装するには
Visual Studio で CourseManager ソリューションを開きます。
ソリューション エクスプローラで、School.edmx ファイルをダブルクリックします。
Entity Data Model デザイナ (エンティティ デザイナ) で School.edmx ファイルが開きます。
OnlineCourse エンティティ型を右クリックし、[プロパティ] をクリックします。
[プロパティ] ウィンドウで、[基本データ型] プロパティを Course に設定します。
OnsiteCourse エンティティ型について、手順 3. と 4. を繰り返します。
OnlineCourse エンティティ型と Course エンティティ型の間のアソシエーション (線) を右クリックします。[削除] をクリックします。
OnsiteCourse エンティティ型と Course エンティティ型の間のアソシエーションを右クリックします。[削除] をクリックします。
OnlineCourse エンティティ型の CourseID プロパティを右クリックし、[削除] をクリックします。
OnsiteCourse エンティティ型の CourseID プロパティを右クリックし、[削除] をクリックします。
Course エンティティ型を選択します。[プロパティ] ウィンドウで、[抽象] プロパティを true に設定します。
エンティティ型を抽象型として定義するとその型の既存の関数マッピングがすべて削除されることを通知するメッセージ ボックスが表示されます。[OK] をクリックします。
[!メモ]
Course エンティティ型が抽象型に変更されたため、元の CourseManager アプリケーションの更新機能は動作しなくなります。
OnlineCourse エンティティ型を右クリックし、[テーブル マッピング] をクリックします。
[マッピングの詳細] ウィンドウが表示されます。
CourseID 列に対応する [値/プロパティ] フィールドをクリックします。
[値/プロパティ] フィールドは、対応する列にマップできるプロパティを示すドロップダウン リストになります。
ドロップダウン リストから [CourseID] を選択します。
OnsiteCourse エンティティ型について、手順 11. と 13. を繰り返します。
これで、Table-Per-Type 継承が実装されました。
ユーザー インターフェイスの構築
次に、CourseDiscrimForm フォームを読み込んで表示するボタンを CourseViewer フォームに追加します。さらに、OnsiteCourses および OnlineCourses を表示するための 2 つの DataGridView コントロールを追加します。最後に、DataGridView を BindingSource コントロールにバインドします。オブジェクトをコントロールにバインドする方法の詳細については、「コントロールへのオブジェクトのバインド (Entity Framework)」を参照してください。
ユーザー インターフェイスを構築するには
ソリューション エクスプローラで CourseManager プロジェクトを右クリックし、[追加] をポイントして、[新しい項目] をクリックします。
[新しい項目の追加] ダイアログ ボックスが表示されます。
[Windows フォーム] を選択し、[追加] をクリックします。
新しいフォームがプロジェクトに追加され、フォーム デザイナで開かれます。
[プロパティ] ウィンドウで、フォーム名を CourseDiscriminator に設定します。
新しいフォームがプロジェクトに追加され、フォーム デザイナで開かれます。フォーム名が CourseDiscriminator に、テキストが CourseDiscriminator に設定されます。
ComboBox コントロールをツールボックスからフォームにドラッグし、[プロパティ] ウィンドウで名前を departmentList に設定します。
DataGridView コントロールをツールボックスからフォームにドラッグし、名前を onsiteGridView に設定します。
別の DataGridView コントロールをツールボックスからフォームにドラッグし、名前を onlineGridView に設定します。
ソリューション エクスプローラで、CourseViewer.cs または CourseViewer.vb をダブルクリックします。
CourseViewer フォームのデザイン ビューが表示されます。
Button コントロールをツールボックスから CourseViewer フォームにドラッグします。
[プロパティ] ウィンドウで、Button の名前を viewDiscriminator に設定し、ボタンのテキストを Online vs. Onsite に設定します。
viewDiscriminatorButton をダブルクリックします。
フォームの分離コード ファイルが開きます。
viewDiscriminator_click イベント ハンドラに次のコードを追加します。
Dim courseDiscrim As New CourseDiscriminator courseDiscrim.Visible = True
CourseDiscriminator courseDiscrim = new CourseDiscriminator(); courseDiscrim.Visible = true;
このフォームのユーザー インターフェイスが完成しました。
EDM に対するクエリ
この手順では、EDM に対してクエリを実行し、結果を Windows フォーム コントロールにバインドします。
EDM に対してクエリを実行するには
フォーム デザイナで CourseDiscriminator フォームを開きます。
BindingSource コントロールをツールボックスからフォームにドラッグします。
[プロパティ] ウィンドウで、BindingSource の名前を onsiteBindingSource に設定します。
[プロパティ] ウィンドウで、DataSource プロパティの横にあるフィールドをクリックします。
フィールドは、使用可能なデータ ソースを示すドロップダウン リストになります。
[プロジェクト データ ソースの追加] をクリックします。
データ ソース構成ウィザードの [データ ソースの種類を選択] ウィンドウが開きます。
[アプリケーションのデータの取得元] ボックスで、[オブジェクト] をクリックします。
[次へ] をクリックします。
[バインド先のオブジェクトを選択します。] ウィンドウが開きます。使用可能なリソースのツリーの最上位ノードが表示されます。
CourseManager ノードを展開し、SchoolModel (C#) または CourseManager.SchoolModel (Visual Basic) ノードを展開します。
OnsiteCourse を選択し、[完了] をクリックします。
手順 2. ~ 9. を繰り返します。ただし、BindingSource コントロールの名前は OnlineBindingSource とし、OnlineCourse オブジェクトにバインドします。
OnsiteGridView コントロールを右クリックし、[プロパティ] をクリックします。
[プロパティ] ウィンドウで、DataSource プロパティの横にあるフィールドをクリックします。
フィールドは、使用可能なデータ ソースを示すドロップダウン リストになります。
OnsiteBindingSource を選択します。
OnlineGridView について、手順 11. ~ 13. を繰り返します。ただし、DataSouce プロパティは OnlineBindingSource に設定します。
[!メモ]
OfType メソッドは、DataGridView コントロールが実行時に列を生成できない列挙を返します。この例で目的の情報を表示するには、バインド対象のクラスに基づいて、デザイン時に DataGridView コントロール用のデータ ソースを BindingSource コントロールを使用して設定します。
CourseDiscriminator フォームをダブルクリックします。
CourseDiscriminator フォームの分離コード ファイルが開きます。
次の using (C#) ステートメントまたは Imports (Visual Basic) ステートメントを追加して、School データベースから作成されたモデルとエンティティの名前空間を参照します。
Imports System.Data.Objects Imports System.Data.Objects.DataClasses
using System.Data.Objects; using System.Data.Objects.DataClasses;
データ コンテキストを表すプロパティを CourseDiscriminator クラスに追加します。
' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities
// Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
CourseDiscriminator_Load イベント ハンドラで、オブジェクト コンテキストを初期化して、Department 情報を返すクエリに departmentList コントロールをバインドするコードを追加します。
' Initialize the ObjectContext. schoolContext = New SchoolEntities() ' Define a query that returns all Department objects and ' related Course objects, ordered by name. Dim departmentQuery As ObjectQuery(Of Department) = _ schoolContext.Department.Include("Course") _ .OrderBy("it.Name") ' Bind the ComboBox control to the query, which is ' executed during data binding. departmentList.DataSource = departmentQuery _ .Execute(MergeOption.OverwriteChanges) departmentList.DisplayMember = "Name"
// Initialize the ObjectContext. schoolContext = new SchoolEntities(); // Define a query that returns all Department objects // and related Course objects, ordered by name. ObjectQuery<Department> departmentQuery = schoolContext.Department.Include("Course") .OrderBy("it.Name"); // Bind the ComboBox control to the query, which is // executed during data binding. this.departmentList.DataSource = departmentQuery .Execute(MergeOption.OverwriteChanges); this.departmentList.DisplayMember = "Name";
CourseDiscriminator フォームのデザイナ ビューに戻り、departmentListComboBox コントロールをダブルクリックします。
分離コード ファイルが開きます。departmentList_SelectedIndexChanged イベント ハンドラがコードに追加されました。
departmentList_SelectedIndexChanged イベント ハンドラに次のコードを追加して、BindingSource コントロールのデータ ソースを更新します。
' Get the selected department object. Dim department As Department = CType(Me.departmentList. _ SelectedItem, Department) ' Update the data sources for the BindingSource controls. onsiteBindingSource.DataSource = department.Course _ .OfType(Of OnsiteCourse)() onlineBindingSource.DataSource = department.Course _ .OfType(Of OnlineCourse)()
// Get the selected department object. Department department = (Department)this.departmentList .SelectedItem; // Update the data sources for the BindingSource controls. onsiteBindingSource.DataSource = department.Course .OfType<OnsiteCourse>(); onlineBindingSource.DataSource = department.Course .OfType<OnlineCourse>();
アプリケーションが完成しました。Ctrl キーを押しながら F5 キーを押してアプリケーションを実行します。[Onsite vs. Online] ボタンをクリックして、CourseDiscriminator フォームを読み込みます。選択した部門用の OnsiteCourses と OnlineCourses が DataGridView コントロールに表示されます。
コード リスト
このセクションでは、CourseDiscriminator フォームの分離コード ファイルの最終バージョンを示します。
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class CourseDiscriminator
' Create an ObjectContext instance based on SchoolEntity.
Private schoolContext As SchoolEntities
Private Sub CourseDiscriminator_Load(ByVal sender As System. _
Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Initialize the ObjectContext.
schoolContext = New SchoolEntities()
' Define a query that returns all Department objects and
' related Course objects, ordered by name.
Dim departmentQuery As ObjectQuery(Of Department) = _
schoolContext.Department.Include("Course") _
.OrderBy("it.Name")
' Bind the ComboBox control to the query, which is
' executed during data binding.
departmentList.DataSource = departmentQuery _
.Execute(MergeOption.OverwriteChanges)
departmentList.DisplayMember = "Name"
End Sub
Private Sub departmentList_SelectedIndexChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
departmentList.SelectedIndexChanged
' Get the selected department object.
Dim department As Department = CType(Me.departmentList. _
SelectedItem, Department)
' Update the data sources for the BindingSource controls.
onsiteBindingSource.DataSource = department.Course _
.OfType(Of OnsiteCourse)()
onlineBindingSource.DataSource = department.Course _
.OfType(Of OnlineCourse)()
End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
namespace CourseManager
{
public partial class CourseDiscriminator : Form
{
// Create an ObjectContext instance based on SchoolEntity.
private SchoolEntities schoolContext;
public CourseDiscriminator()
{
InitializeComponent();
}
private void CourseDiscriminator_Load(object sender,
EventArgs e)
{
// Initialize the ObjectContext.
schoolContext = new SchoolEntities();
// Define a query that returns all Department objects
// and related Course objects, ordered by name.
ObjectQuery<Department> departmentQuery =
schoolContext.Department.Include("Course")
.OrderBy("it.Name");
// Bind the ComboBox control to the query, which is
// executed during data binding.
this.departmentList.DataSource = departmentQuery
.Execute(MergeOption.OverwriteChanges);
this.departmentList.DisplayMember = "Name";
}
private void departmentList_SelectedIndexChanged(object sender,
EventArgs e)
{
// Get the selected department object.
Department department = (Department)this.departmentList
.SelectedItem;
// Update the data sources for the BindingSource controls.
onsiteBindingSource.DataSource = department.Course
.OfType<OnsiteCourse>();
onlineBindingSource.DataSource = department.Course
.OfType<OnlineCourse>();
}
}
}
次の手順
EDM に Table-Per-Type 継承を正常に実装できました。Table-Per-Type 継承を持つ EDM を定義する方法の詳細については、「Table-Per-Type 継承でモデルを定義する方法 (Entity Framework)」を参照してください。Entity Framework を使用するアプリケーションを構築する方法の詳細については、「プログラミング ガイド (Entity Framework)」を参照してください。
参照
その他のリソース
ADO.NET Entity Data Model デザイナのシナリオ
Entity Data Model ツールのタスク