第5回 Hibernateでインテグレーション層のDAOデザインを考える

  Page.1 Page.2

   Hibernate O/Rマッピング:XML vs. アノーテーション

 ドメイン・オブジェクトとして定義したJavaのクラスとデータベース・テーブルとの間のマッピングを行うことをO/Rマッピングと呼びます。HibernateのO/Rマッピングの情報は、XML形式で定義します。一方、EJB 3.0ではアノーテーションを用いて、ドメイン・オブジェクトのJavaクラスに直接記述することができるようになります。

 また、Hibernate用に記述したXML形式のマッピング情報は、EJB 3.0のアノーテーションへ容易に書き直すことができます。以下にHibernateを用いた場合のO/Rマッピング情報の例を示します。

リスト8 O/Rマッピング情報(Hibernateの場合)
<hibernate-mapping>
  <class name="com.example.model.CustomerBO" 
         table="TBL_CUSTOMER">

    <!-- プライマリー・キー -->
    <id name="id"
        type="int"
        unsaved-value="0"
        column="ID">
      <generator class="sequence">
        <param name="sequence">ID_TBL_CUSTOMER</param>
      </generator>
    </id>
        :
  </class>
</hibernate-mapping>  

 上記は、顧客情報テーブルTBL_CUSTOMERをCustomerBOクラスにマッピングした場合の例です。プライマリ・キーは、<id>タグでカラム名とCustomerBOのプロパティ名をマッピングし、<generator>タグで、プライマリ・キーの割り当て方法を指定しています。

 これと、同等のマッピング情報をEJB 3.0のアノーテーションを用いて記述し直すと以下のようになります。

リスト9 O/Rマッピング情報(EJB 3.0の場合)
@Entity
@Table(name="TBL_CUSTOMER")
public class CustomerBO implements Serializable {
    private int id;

    @Id(generate=GeneratorType.SEQUENCE, generator="ID_TBL_CUSTOMER")
    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }
        :
}

 テーブル名やプライマリ・キーのレベルでは、Hibernateマッピング情報をEJB 3.0のアノーテーションに直すのは非常に直観的に作業できることが分かります。

 次は、Hibernateのコンポジションの例を見てみましょう。データベースのテーブルは、パフォーマンスを優先するため、きれいなドメイン・モデルをあえて崩し、非正規化を行って、複数のエンティティを1つのテーブルに詰め込んで定義される場合があります。Hibernateには、1つのテーブルを複数のJavaクラスにマッピングし、Javaの世界では美しいドメイン・モデルのままデータ操作ができる機能があります。例えば、テーブルTBL_CUSTOMERには、姓(NAME_LAST)と名(NAME_FIRST)の2つのカラムがありますが、これをCustomerNameBOクラスとしてCustomerBOクラスから分離して扱いたいとします。この場合の、Hibernateマッピング定義は以下のようになります。

リスト10 コンポジションの例(Hibernateの場合)
<component name="name"
               class="com.example.model.CustomerNameBO">
      <property name="first"
                type="java.lang.String"
                column="NAME_FIRST"
                not-null="true"
                length="20" />
      <property name="last"
                type="java.lang.String"
                column="NAME_LAST"
                not-null="true"
                length="20" />
    </component>
    <property name="email"
              type="java.lang.String"
              column="EMAIL"
              length="50" />

 コンポジションの概念はEJB 3.0にも引き継がれています。EJB 3.0では<component>タグの代わりに、アノーテーション@Embeddedと@Embeddableを用います。

リスト11 コンポジションの例(EJB3.0の場合)
@Entity
@Table(name="TBL_CUSTOMER")
public class CustomerBO implements Serializable {
        :
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="last", column=@Column(name="NAME_LAST")),
        @AttributeOverride(name="first", column=@Column(name="NAME_FIRST"))
    })
    public CustomerNameBO getName() {
        return this.name;
    }
}

@Embeddable
public class CustomerNameBO implements Serializable {
    private String first;
    private String last;
        :
}

 フォーリン・キーを用いたテーブル間の関連もHibernateからEJB 3.0に引き継がれています。特に、関連のあるテーブル・レコードを更新したり、削除した場合のcascadeモードについても、同じ振る舞いをするように定義することが可能です。CustomerBOからCompanyBOに、多対一(many-to-one)関連を持つ場合のHibernateの例をリスト12に、EJB 3.0の例をリスト13に示します。両者を見比べてみてください。

リスト12 多対一関連の例(Hibernateの場合)
<many-to-one name="company"
       cascade="save-update"
       class="com.example.model.CompanyBO"
       not-null="true">
   <column name="COMPANY_ID" />
</many-to-one>

リスト13 多対一関連の例(EJB3.0の場合)
@Entity
@Table(name="TBL_CUSTOMER")
public class CustomerBO implements Serializable {
        :
    @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinColumn(name="COMPANY_ID", nullable=false)
    public CompanyBO getCompany() {

        return this.company;
    }
}

 このように、Hibernateを用いて定義されたドメイン・モデルのクラスはEJB 3.0でもそのまま利用することができ、XMLで定義されたO/Rマッピング情報からEJB 3.0のアノーテーションへの変換は問題なく作業できることが分かっていただけると思います。

 また、HibernateのEJB 3.0仕様の取り込みは急ピッチで進められており、Hibernate 3.1からはXML形式の代わりにEJB 3.0ドラフト仕様に基づくアノーテーションやEntityManagerのインターフェイスを利用することもできるようになっています。Hibernate 3.1はまだベータ段階ですので、これらをすぐ実際の開発プロジェクトで採用するのは難しいとは思いますが、評価のために使用してみるのもよいでしょう。

   まとめ

 以上、5回の連載を通じて、将来にわたって再利用可能なアプリケーション・コンポーネントを開発するポイントを紹介してきました。将来、Java EE 5環境が利用可能になったとき、実際に行う移行作業は、SpringフレームワークとHibernateのXMLベースの設定ファイルをEJB 3.0のアノーテーションとして定義し直すことが主な作業になるでしょう。ここで紹介した準備を行っておけば、アプリケーションのソースコードのほとんどはJava EE 5でそのまま利用可能であることが理解いただけたと思います。

 本連載を通じて解説に利用したサンプルのソースコードを見ていただけると分かるのですが、プレゼンテーション層、ビジネス層、インテグレーション層のすべてにわたって、Springフレームワークの機能を利用しているにもかかわらず、アプリケーションのソースコードには、Springフレームワークのクラスへの直接の依存関係が全く存在しないことが分かります。これは、Springフレームワークの制御の反転(IoC:Inversion of Control)がとてもうまく機能し、アプリケーション・コンポーネントがPOJOとして高い独立性を示した1つの重要な結果です。

 最後に、本連載が、皆さんのアプリケーション開発をもっと簡単に、そして楽しくできるきっかけになれば幸いです。

2/2  

 INDEX

第5回 Hibernateでインテグレーション層のDAOデザインを考える
  Page1
EJB 3.0のEntityManager
EntityManagerのライフサイクル
SpringのAOPを用いてHibernate Sessionのライフサイクルを管理する
Hibernateを用いたデータアクセス
Page2
Hibernate O/Rマッピング:XML vs. アノーテーション



Java Solution全記事一覧



Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間