あなたがやってるDB周りの実装は無駄かもしれませんよ？JPAでSQLいらず。

> この投稿は[JavaEEのアーキテクチャを再興する。（まとめページ）](http://qiita.com/ukiuni@github/items/b9d18b44570ece0e3933)に属する投稿です。他の記事もお楽しみあれ。

JavaでWebシステムを作るとき、たいていはRDBも触ると思います。JavaでEntityを作成して、それと同じ形でDBのCreate文を作成して、フィールド名かカラム名をTypoしてバグを埋め込む。みなさんも一度は体験したことがあるかと存じます。
JPA2.0を使うと、JPAがEntityからRDBのテーブルを作成してくれるので、Create文を見ることなく、RDBにオブジェクトを保存できます。db:migrateとかコマンドも打つことなく、JPAがすべてを整えてくれます。便利。

本稿では、システムを作る上では絶対に出てくる、テーブル同士の関連をJPAで表現するためにはどうするかをお伝えします。
とはいえ、Javaの普通の関連を作り、アノテーションを貼るだけです。前置きよりも簡単に読めるかと思います。

なお、JPAの簡単な説明は[こちら](http://qiita.com/ukiuni@github/items/f3e68e7f8fdcc0830e06)をご覧ください。

# サンプル
サンプルはGithubの[こちら](https://github.com/ukiuni/EclipseLinkInspect)に乗せてあります。
[RelationMain.java](https://github.com/ukiuni/EclipseLinkInspect/blob/master/src/org/ukiuni/jpaInspect/RelationMain.java)で、[Cart](https://github.com/ukiuni/EclipseLinkInspect/blob/master/src/org/ukiuni/jpaInspect/entity/Cart.java)と[Item](https://github.com/ukiuni/EclipseLinkInspect/blob/master/src/org/ukiuni/jpaInspect/entity/Item.java)というクラスを保存、取得を行っています。
サンプルではJPAの実装として、EclipseLink、RDBにH2を使用しています。

# 解説
まずは保存対象のクラスを見ていきます。

```java:Item.java抜粋(関連を定義している部分)
@ManyToOne(cascade = CascadeType.ALL)
private Cart cart;
```

```java:Cart.java抜粋(関連を定義している部分)
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL)
private List<Item> items = new ArrayList<Item>();
```

ItemとCartそれぞれでお互いを参照しています。また、@ManyToOne、@OneToManyでそれぞれの関係性を定義しています。cascadeは、関連付けを保存時や参照時に有効にするかを選択します。ここではすべての場合で関連付けを有効にしたいので、CascadeType.ALLを指定しています。また、mappedByでは関連先、Itemのフィールド名を指定しています。
関連付けはこれだけ。簡単ですね。

```java:RelationMain.java抜粋(保存時)
Cart cart = new Cart();

cart.addItem(new Item("ITEM1"));
cart.addItem(new Item("ITEM2"));

cart.setKey(UUID.randomUUID().toString());

em.persist(cart);
```

cartを作成し、itemを関連付けています。Cart#addItemでは、Itemとcartを相互に関連付けています。
これだけでDBに外部キー関連が保存されます。

```java:RelationMain.java抜粋(Cart検索時)
List<Cart> carts = em.createQuery(cq.select(r)).getResultList();
System.out.println("carts length = " + carts.size());
for (Cart cart : carts) {
    System.out.println("# cart id = " + cart.getId());
    List<Item> items = cart.getItems();
    for (Item item : items) {
        System.out.println("\t item id = " + item.getId() + ", name = " + item.getName() + ", cartId");
    }
}
```

Cartを検索すると、Itemも一緒に取得できることがわかります。
逆に、Itemを検索しても、Cartが取得できます。

```java:RelationMain.java抜粋(Item検索時)
List<Item> items = em.createQuery(query.select(r)).getResultList();
System.out.println("items length = " + items.size());
for (Item item : items) {
    System.out.println("item cartId = " + item.getCart().getId() + " id = " + item.getId() + ", name = " + item.getName());
}
```

RDBを使っていることを意識せずに保存、取得ができていますね！

# 更に詳しく見てみる。

JPAは便利すぎます！しかしながら、どういう処理をしているかとても気になるので、中を見てみます。

## テーブル定義
JPAでは勝手にテーブルを作ってくれています。どのようなテーブルができているか見てみます。

```sql:テーブル定義
CREATE CACHED TABLE PUBLIC.ITEM(
    ID BIGINT NOT NULL,
    NAME VARCHAR,
    CART_ID BIGINT
);
CREATE PRIMARY KEY PUBLIC.PRIMARY_KEY_2 ON PUBLIC.ITEM(ID);
eALTER TABLE PUBLIC.ITEM ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID) INDEX PUBLIC.PRIMARY_KEY_2,  
JCREATE CACHED TABLE PUBLIC.CART(
    ID BIGINT NOT NULL,
    KEY VARCHAR
);
CREATE PRIMARY KEY PUBLIC.PRIMARY_KEY_1F ON PUBLIC.CART(ID);
ALTER TABLE PUBLIC.CART ADD CONSTRAINT PUBLIC.CONSTRAINT_1F PRIMARY KEY(ID) INDEX PUBLIC.PRIMARY_KEY_1;
CREATE INDEX PUBLIC.FK_ITEM_CART_ID_INDEX_2 ON PUBLIC.ITEM(CART_ID);
ALTER TABLE PUBLIC.ITEM ADD CONSTRAINT PUBLIC.FK_ITEM_CART_ID FOREIGN KEY(CART_ID) INDEX PUBLIC.FK_ITEM_CART_ID_INDEX_2 REFERENCES PUBLIC.CART(ID) NOCHECK;
```
ITEMテーブルにCART_IDというカラムができて、ALTER　TABLEでそこに外部キーを張っているのがわかります。

## Select文
EclipseLinkのログをアプリの出力と交えて見てみます。

```:ログ
query cart start
[EL Fine]: sql: 2014-06-27 23:09:07.716--ServerSession(253338012)--Connection(1998581014)--Thread(Thread[main,5,main])--SELECT ID, KEY FROM CART
carts length = 3
# cart id = 1
[EL Fine]: sql: 2014-06-27 23:09:07.721--ServerSession(253338012)--Connection(1998581014)--Thread(Thread[main,5,main])--SELECT ID, NAME, CART_ID FROM ITEM WHERE (CART_ID = ?)
	bind => [1]
	 item id = 2, name = ITEM1, cartId
	 item id = 3, name = ITEM2, cartId

```

Cartの検索はSELECT ID, KEY FROM CARTで普通に行っていますね。興味深いのは、この時はまだItemは取得しておらず、cart.getItems()の時に初めてSELECT ID, NAME, CART_ID FROM ITEM WHERE (CART_ID = ?)を行っているのがわかります。これで余分なデータ取得をすることがなくてハッピーですね。

# JPAはとても簡単。使わない手はありません。
DBアクセスのような、いつもいつも同じコードを書くような実装は、できるだけ楽をして作って、UXや便利な機能などに力を入れ、ものづくりの価値を上げたいものです。
そのためにも、JPAを使ってみてはいかがでしょうか？