複合型 - EF デザイナー
このトピックでは、複合型を Entity Framework デザイナー (EF デザイナー) にマップする方法と、複合型のプロパティを含むエンティティのクエリを実行する方法について説明します。
次の図は、EF Designer での作業時に使用されるメイン ウィンドウを示しています。
Note
概念モデルをビルドすると、マップされていないエンティティとアソシエーションについての警告が [エラー一覧] に表示される場合があります。 モデルからデータベースを生成することを選択すると、エラーが解消されるため、これらの警告は無視してかまいません。
複合型とは
複合型はエンティティ型の非スカラー プロパティで、これによってスカラー プロパティをエンティティ内で整理できます。 エンティティと同様に、複合型はスカラー プロパティまたは他の複合型プロパティで構成されています。
複合型を表すオブジェクトを操作する場合は、次の点に注意してください。
- 複合型にはキーがないため、独立して存在することができません。 複合型は、エンティティ型またはその他の複合型のプロパティとしてのみ存在できます。
- 複合型は、アソシエーションに参加できず、ナビゲーション プロパティを含めることができません。
- 複合型プロパティを null にすることはできません。 DbContext.SaveChanges が呼び出され、null 複合オブジェクトが検出されると、**InvalidOperationException** が発生します。 複合オブジェクトのスカラー プロパティは、null にできます。
- 複合型は他の複合型を継承できません。
- 複合型は、class として定義する必要があります。
- DbContext.DetectChanges が呼び出されると、EF は複合型オブジェクトのメンバーに対する変更を検出します。 DbSet.Find、DbSet.Local、DbSet.Remove、DbSet.Add、DbSet.Attach、DbContext.SaveChanges、DbContext.GetValidationErrors、DbContext.Entry、DbChangeTracker.Entries メンバーが呼び出されると、Entity Framework によって DetectChanges が自動的に呼び出されます。
エンティティのプロパティを新しい複合型にリファクタリングする
概念モデル内に既にエンティティがある場合は、一部のプロパティを複合型プロパティにリファクタリングしたい場合があります。
デザイナー サーフェイスで、エンティティの 1 つまたは複数のプロパティ (ナビゲーション プロパティ以外) を選択し、右クリックして [リファクター] -> [新しい複合型に移動] を選択します。
選択したプロパティを含む新しい複合型がモデル ブラウザーに追加されます。 複合型には既定の名前が付きます。
新しく作成した型の複合プロパティが、選択したプロパティと置き換わります。 プロパティのマッピングはすべて保持されます。
新しい複合型を作成する
既存のエンティティのプロパティを含まない、新しい複合型を作成することもできます。
モデル ブラウザーで [複合型] フォルダーを右クリックし、[新しい複合型の追加] をポイントします。 または、[複合型] フォルダーを選択し、キーボードの Insert キーを押します。
既定の名前を持つ新しい複合型がフォルダーに追加されます。 これで、型にプロパティを追加できるようになりました。
プロパティを複合型に追加する
複合型のプロパティはスカラー型か既存の複合型にすることができます。 ただし、複合型のプロパティに循環参照を含めることはできません。 たとえば、複合型 OnsiteCourseDetails に、複合型 OnsiteCourseDetails のプロパティを含めることはできません。
以下のいずれかの方法で、複合型にプロパティを追加できます。
モデル ブラウザーで複合型を右クリックし、[追加] をポイントしてから、[スカラー プロパティ] または [複合プロパティ] をポイントし、目的のプロパティ型を選択します。 または、複合型を選択し、キーボードの Insert キーを押します。
既定の名前を持つ新しいプロパティが複合型に追加されます。
または -
EF デザイナー サーフェイスでエンティティ プロパティを右クリックし、[コピー] を選択してから、モデル ブラウザーで複合型を右クリックし、[貼り付け] を選択します。
複合型の名前を変更する
複合型の名前を変更すると、その型へのすべての参照がプロジェクト全体で更新されます。
モデル ブラウザーで複合型をゆっくりとダブルクリックします。 名前が選択され、編集モードになります。
または -
モデル ブラウザーで複合型を右クリックし、[名前の変更] を選択します。
または -
モデル ブラウザーで複合型を選択し、F2 キーを押します。
または -
モデル ブラウザーで複合型を右クリックし、[プロパティ] を選択します。 [プロパティ] ウィンドウで名前を編集します。
既存の複合型をエンティティに追加し、そのプロパティをテーブル列にマップする
エンティティを右クリックし、[新規追加] をポイントして、[複合プロパティ] を選択します。 既定の名前を持つ複合型プロパティがエンティティに追加されます。 既存の複合型から選択した既定の型がプロパティに割り当てられます。
[プロパティ] ウィンドウでプロパティに目的の型を割り当てます。 複合型プロパティをエンティティに追加した後、そのプロパティをテーブル列にマップする必要があります。
デザイン サーフェイスまたはモデル ブラウザーでエンティティ型を右クリックして、[テーブル マッピング] を選択します。 [マッピングの詳細] ウィンドウにテーブル マッピングが表示されます。
[<テーブル名> にマップ] ノードを展開します。 [列マッピング] ノードが表示されます。
[列マッピング] ノードを展開します。 テーブル内のすべての列の一覧が表示されます。 列がマップされる既定のプロパティが [値/プロパティ] 見出しの下に表示されます (ある場合)。
マップする列を選択して、対応する [値/プロパティ] フィールドを右クリックします。 すべてのスカラー プロパティのドロップダウン リストが表示されます。
適切なプロパティを選択します。
各テーブル列ごとに、手順 6. と 7. を繰り返します。
Note
列マッピングを削除するには、マップする列を選択し、[値/プロパティ] フィールドをクリックします。 その後、ドロップダウンの一覧で [削除] を選択します。
関数インポートを複合型にマップする
関数インポートは、ストアド プロシージャに基づいています。 関数インポートを複合型にマップするには、対応するストアド プロシージャが返す列の数が複合型のプロパティの数と一致するようにし、ストレージ型がプロパティ型と互換性があるようにする必要があります。
複合型にマップするインポートされた関数をダブルクリックします。
新しい関数インポートの設定を、次のように入力します。
関数インポートを作成するストアド プロシージャを [ストアド プロシージャ名] フィールドで指定します。 このフィールドは、ストレージ モデル内のすべてのストアド プロシージャが表示されるドロップダウン リストです。
関数インポートの名前を [関数インポート名] フィールドで指定します。
戻り値の型として [複合] を選択し、ドロップダウン リストから適切な型を選択して特定の戻り値の複合型を指定します。
[OK] をクリックします。 関数インポート エントリが概念モデルに作成されます。
関数インポートの列マッピングをカスタマイズする
- モデル ブラウザーで関数インポートを右クリックし、[関数インポート マッピング] を選択します。 [マッピングの詳細] ウィンドウが表示され、関数インポートの既定のマッピングが表示されます。 矢印は、列の値とプロパティの値の間のマッピングを示します。 既定では、列名は、複合型のプロパティ名と同じであるものとされます。 既定の列名は、グレーのテキストで表示されます。
- 必要に応じて、関数インポートに対応するストアド プロシージャにより返される列名と一致するように、列名を変更します。
複合型を削除する
複合型を削除すると、概念モデルからその型が削除され、その型のすべてのインスタンスのマッピングが削除されます。 ただし、その型への参照は更新されません。 たとえば、エンティティに型 ComplexType1 の複合型プロパティがあり、モデル ブラウザーで ComplexType1 が削除された場合、対応するエンティティ プロパティは更新されません。 モデルが検証されません。削除された複合型を参照するエンティティがモデルに含まれているためです。 エンティティ デザイナーを使用すると、削除された複合型への参照を更新または削除できます。
モデル ブラウザーで複合型を右クリックし、[削除] を選択します。
または -
モデル ブラウザーで複合型を選択し、キーボードの Del キーを押します。
複合型のプロパティを含むエンティティのクエリを実行する
次のコードは、複合型プロパティを含むエンティティ型オブジェクトのコレクションを返すクエリの実行方法を示しています。
using (SchoolEntities context = new SchoolEntities())
{
var courses =
from c in context.OnsiteCourses
order by c.Details.Time
select c;
foreach (var c in courses)
{
Console.WriteLine("Time: " + c.Details.Time);
Console.WriteLine("Days: " + c.Details.Days);
Console.WriteLine("Location: " + c.Details.Location);
}
}
.NET