はじめに
JPA(Java Persistence API)とは、オブジェクトの世界からリレーショナルの世界へ、あるいはその逆への変換を行うためのAPIです。
前編では、JPAを使用した1テーブルに対するCRUD操作を行うための実装方法を説明しました。後編となる今回は、複数のテーブルに対するCRUD操作について解説していきます。
ディレクションとカーディナリティのトラウマ
オブジェクトモデルの世界でEntity間の関連は、ディレクションとカーディナリティという2つの軸を組み合わせます。Entity間の関連の扱い方は非常に難しいと思われがちです。特にEJB2.1以前のCMPを使った設計やコーディングの経験のある方は、設定ファイルにしろコーディングにしろ、学習も困難・実装も困難ということでトラウマとなったと思います。
筆者自身もEJB2.1で多くのCMPを記述し、その困難さを身をもって知った技術者の1人です。そこで、Javaの世界はEJBからPOJOの世界へと一気に流れが変わったように思えます。しかし、EJBにはそれなりの魅力があることも確かです。ライフサイクルの管理をはじめ、多くの面倒な処理をEJBコンテナが行ってくれるからです。
Session Bean+JPA
上記のトラウマこそ、筆者がEJBを捨てPOJOに逃げ込んだ原因です。とは言いつつも、JPA自体はPOJOをベースに作られているということからすれば、EJBの世界にJPAというPOJOベースのO/Rマッピングの技術が持ち込まれたことになり、Session BeanとJPAの組み合わせはEJBとPOJOのいいとこ取りをしていることになります。前編ではJavaアプリケーションを使いJPAを説明しましたが、今回は、EJBを使用した場合、いかに便利になるかを実感していただければと思います。
ディレクションとカーディナリティ
ディレクション
オブジェクトモデルのディレクションは参照のフィールドの保持により決定します。AクラスとBクラスが存在し、AクラスがBクラスの参照のフィールドは持つが、BクラスはAクラスの参照のフィールドを持たない場合、単方向となります。クラス図ではAからBへの矢印で表します。AクラスとBクラスが互いの参照のフィールドを持つ場合、双方向となります。クラス図ではAとBの間に両方向の矢印で表します。
カーディナリティ
オブジェクトモデルのカーディナリティは、参照のフィールドがコレクションか否かで決定します。AクラスとBクラスが存在し、それぞれ次のように呼ばれます。
- 1対1(One-to-one):AクラスがBクラスのコレクションではない参照のフィールドを持ち、BクラスはAクラスへの参照を持たない場合、またはその逆の場合、さらにはお互いコレクションではない参照のフィールドを持つ場合のAクラスとBクラス
- 1対多(One-to-many):AクラスがBクラスの参照のフィールドをコレクションとして持つ場合(BクラスはAクラスのコレクションではない参照を持っても構わない)のAクラスとBクラス
- 多対1(Many-to-one):BクラスがAクラスの参照のフィールドをコレクションとして持つ場合(AクラスはBクラスのコレクションではない参照を持っても構わない)のAクラスとBクラス
- 多対多(Many-to-many):AクラスがBクラスの参照のフィールドをコレクションとして持ち、BクラスもAクラスの参照のフィールドのコレクションを持つ場合のAクラスとBクラス
関連はディレクションとカーディナリティの組み合わせ
関連のパターンはディレクションで2つ(単方向、双方向)、カーディナリティで4つ(One-to-one、One-to-many、Many-to-one、Many-to-many)があり、その組み合わせは単純に計算すると8つとなります。
関連のパターンをクラス図で示すと次のようになります。ディレクションとカーディナリティはAクラスを基準としています。Many-to-manyの場合、単方向はないので、実質的には7つのパターンが存在します。これらのパターンを整理したのは@OneToOne、@OneToMany、@ManyToOne、@ManyToManyなどのアノテーションをEntityクラスのカラムに付与する必要があるためです。以下ではコレクションとしてListを使用していますが、SetやMapも使用可能です。
One-to-one
![単方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_1s.gif)
![双方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_4s.gif)
One-to-many
![単方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_2s.gif)
![双方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_5s.gif)
Many-to-one
![単方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_3s.gif)
![双方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_6s.gif)
Many-to-many
- 単方向:該当無し
![双方向](http://cz-cdn.shoeisha.jp/static/images/article/5061/1_7s.gif)
主と従
双方向の場合、主と従という関係があります。これはオブジェクトモデルではなく、リレーショナルモデルを元に決定します。双方向でMany-to-manyの場合は、どちらも主であり従となることができます。それ以外の双方向は、RDBの外部キーを持っているテーブルを表現しているEntityオブジェクト側が主となり、外部キーを持っていないテーブルを表現しているEntityオブジェクト側が従となります。
Entityクラスのアノテーション
関連を持つフィールドの場合、ディレクションとカーディナリティの7つのパターン、および主と従という関係が理解できていれば適切にアノテーションを付与することが可能となります。カーディナリティはアノテーションを付与するのみで設定ファイルの変更が必要ないため、非常に分かりやすい記述が可能です。単方向でかつ相手の参照を持たない場合は、Columnアノテーションのみで済みます。