連載:ADO.NET Entity Framework入門

第4回 データベースからのEntity Data Model生成

WINGSプロジェクト 土井 毅 著/山田 祥寛 監修
2010/09/10
Page1 Page2 Page3

複合型の活用

 データベースからのリバースによるEDMの生成を行うと、多対多関係の中間テーブルなどを除き、基本的にテーブル1つに対してエンティティ1つが生成され、エンティティにはテーブルのフィールドに対応するプロパティが生成される。

 通常は、そのままテーブルと同等のエンティティを使用するだけでも問題ないが、複雑な構造のテーブルを扱う際には、多数のフィールドを持つエンティティが生成されてしまうことになる。そういった場合には、複合型という機能を用いることで、概念モデルを見通しよく設計することが可能となる。

 ここでは、複合型の概要について触れ、リバースしたEDMで複合型を作成する。

■複合型とは

 これまで扱ってきたEDMのエンティティのプロパティは、スカラー・プロパティと呼ばれる、数値、文字列などのプリミティブな型であった。EDMは、データベース上のフィールドと1対1に対応するスカラー・プロパティだけでなく、図9のように、複数のスカラー・プロパティで構成される複合型をプロパティとする複合プロパティにも対応している*2

*2 もちろん複合型の中に複合型を入れ子にすることも可能である


図9 複合プロパティを持つエンティティ

 この図9では、Entryエンティティは文字列型のスカラー・プロパティであるNameプロパティと、AddressTypeという名前の複合型であるAddressプロパティを持っている。AddressType複合型は、MailAddress、TelNoという2つのプロパティを持っている。複合型のプロパティも、エンティティの場合と同様、特定のテーブルのフィールドにマッピングされている。

 複合型とエンティティは、表1にあるように複合プロパティ、スカラー・プロパティを内部に持つことができる点で共通している。違いとしては、エンティティが一意なIDであるキー・プロパティ(データベース上では主キーなどで表現される)を持つのに対し、複合型はキー・プロパティを持たないことにある。従って、複合型はエンティティの一部となって、テーブルのいくつかのフィールドにマッピングすることはできるが、エンティティのようにそれ自体をテーブルに対応させることはできない。また、エンティティのようにほかのエンティティとのリレーションシップを持たせることもできない。

エンティティ 複合型
プロパティ 複合プロパティ、スカラー・プロパティを持てる
キー・プロパティ あり なし
マッピング 直接テーブルにマッピング可能 ほかのエンティティの複合プロパティとして、テーブルのフィールドにマッピング可能
リレーションシップ 可能 不可能
表1 エンティティと複合型の違い

 複合型は、論理モデルと概念モデルのギャップを埋めるための手段といえるだろう。データベースの論理モデルは、数値、文字列、日付、バイナリなどのプリミティブな型によるフラットな行列を基本としているため、テーブル内に複合型を持つことはできない*3が、複合型を使用することで、そうした論理モデル側の制限を概念モデル側に持ち込むことなく、扱いやすい構造の概念モデルを設計することができる。

*3 複合型に含めたいフィールドを別のテーブルに切り出してリレーションを設定することで疑似的な複合型として扱えるが、テーブルの切り出しはJOIN処理の回数が増えることもあり、常に理想的な解決手段とはいえない。

■複合型を追加する

 では、エンティティ内に複合型を追加し、概念モデルの構造を改善してみよう。

 今回のサンプルにおいては、論理モデルの制限により、EntryエンティティのMailAddressとTelNoプロパティは、Entriesテーブルの個々のフィールドになっている。しかし本来、これら2つのプロパティは、概念モデルではAddressTypeという型としてまとめて扱いたいところだ。この部分で複合型を利用してみる。

 ADO.NET Entity Data Modelツールで、Entryエンティティの2つのフィールドを[Ctrl]キーを押しながらクリックして選択し、右クリックのコンテキスト・メニューから[新しい複合型へのリファクター]を実行する(図10)。


図10 複合型に含めたいフィールドを選択して[新しい複合型へのリファクター]を実行

 これを実行すると、モデル・ブラウザの概念モデルの[複合型]項目に「ComplexType1」という型が、エンティティには「ComplexProperty」というプロパティが追加される。

 複合型の型名を修正するため、モデル・ブラウザのComplexType1を選択し、「AddressType」に変更する。(図11)


図11 複合型の型名をAddressTypeに変更する

 続けて、エンティティの複合プロパティ名も同様に「Address」に変更する。(図12)


図12 複合プロパティ名をAddressとする

 以上の流れで複合型のプロパティをエンティティに追加することができた。

 なお、図13の[マッピングの詳細]ペインを確認すると分かるとおり、複合プロパティのマッピング先は、これまでどおりEntriesテーブルのMailAddressおよびTelNoフィールドのままである。


図13 [マッピングの詳細]ウィンドウ
複合プロパティ(Address)の各プロパティのマッピング先は、これまでどおりEntriesテーブルのまま。

 複合プロパティの使い方は特別なものではなく、これまでどおりエンティティ・クラスのメンバとしてアクセスが可能である。

 次のリスト4は、複合プロパティを含むエンティティのLINQ to Entitiesによるクエリと、内容表示のサンプルだ。クエリ処理自体は前回とまったく同一で、内容表示の際に、複合プロパティ(Address)を経由して電話番号フィールド(TelNo)にアクセスしている部分だけが変更点である。複合型が.NETのクラス(AddressTypeクラス)として自然に取り扱えることに注目したい。

// 前回と同様にLINQ to Entitiesでクエリ
using (var container = new AddressBookContainer())
{
  var entries = from entry in container.Entries
                where entry.Name == name
                select entry ;
  PrintEntries(entries);
}

……中略……

// 結果表示メソッド
private static void PrintEntries(IQueryable<Entry> entries)
{
  foreach (var entry in entries)
  {
    // 電話番号フィールドに、
    // Address複合プロパティを経由してアクセス
    Console.WriteLine(string.Format(
        "{0} {1}歳 電話番号:{2}",
        entry.Name, entry.Age, entry.Address.TelNo));

    foreach (var cat in entry.Categories)
    {
      Console.WriteLine(
        string.Format(" カテゴリ名:{0}", cat.CategoryName));
    }
  }
}
' 前回と同様にLINQ to Entitiesでクエリ
Using container As New AddressBookContainer()

    Dim entries = From entry In container.Entries
                  Where entry.Name = name
                  Select entry
    PrintEntries(entries)

End Using

……中略……

' 結果表示メソッド
Private Sub PrintEntries(ByVal entries As IQueryable(Of Entry))

  For Each entry In entries

    ' 電話番号フィールドに、
    ' Address複合プロパティを経由してアクセス
    Console.WriteLine(String.Format(
      "{0} {1}歳 電話番号:{2}",
      entry.Name, entry.Age, entry.Address.TelNo))

    For Each cat In entry.Categories
      Console.WriteLine(
        String.Format(" カテゴリ名:{0}", cat.CategoryName))
    Next
  Next
End Sub
リスト4 複合型を含むエンティティのクエリと内容表示

 なお、複合型自体は.NET Framework 3.5のEntity Frameworkでもサポートされていたが、使用するにはXMLファイルを直接編集する必要があった。今回の流れのように、GUIで複合型をデザインする機能は.NET Framework 4からの新機能である。

【コラム】複合型を含むEDMからのデータベース自動生成

 本文中で見たとおり、複合型はデータベースの論理モデルの制限にとらわれず、概念モデルを自由に設計するためのよい手段といえる。

 従って、.NET Framework 4からサポートされた、EDMからのデータベース自動生成においても積極的に活用したいところだが、現状のデータベース自動生成においては、マッピング先のフィールド名を自由に編集することができないという制限がある。複合型内のプロパティは「複合プロパティ名_プロパティ名」という名前で自動生成され、この名前を変更することはできない。

 こうした自動生成の仕様を考えるに、データベース側で適切なフィールド名を設定したうえで、リバースの際に複合型を活用する、というのが現実的なシナリオと思われる。

まとめ

 データベースからのリバースによるEDMの生成機能と、ストアド・プロシージャ、複合型の活用について考えることができた。前述のとおり、データベースからのリバースおよびEDMからのデータベース自動生成処理は何度でも行え、EDMとデータベースを相互に最新の状態に更新することができる。ぜひEDMとデータベースを修正しながら、どのように更新されるのかを確認してほしい。

 また、ストアド・プロシージャは.NETで定義した通常のメソッドと同様に呼び出しが行えるため、前回で説明したネイティブSQLの実行よりも扱いやすいという特徴がある。性能が必要な場面などに活用していこう。

 複合型のサポートの拡大により、論理モデルの制限が概念モデルを縛ることもなくなり、より自然で扱いやすい構造の概念モデルの構築が可能となっている。まだツール側のサポートがやや不便な面もあるが、概念モデルの重要な機能として覚えておこう。

 次回からは、POCO(Plain Old Clr Object)によるエンティティ・クラスの実装を説明する。End of Article

 

 INDEX
  ADO.NET Entity Framework入門
  第4回 データベースからのEntity Data Model生成
    1.データベースからのEDM生成
    2.ストアド・プロシージャの呼び出し
  3.複合型の活用/まとめ
 
インデックス・ページヘ  「ADO.NET Entity Framework入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間