====== S2JDBC ======
Seasarプロジェクトが提供する新しいタイプのオブジェクト・リレーショナル(OR)マッパー。メソッドチェイン(流れるようなインターフェイス)によってクエリを組み立てる。
===== 使い方 =====
セットアップ方法は[[http://s2container.seasar.org/2.4/ja/s2jdbc.html|公式マニュアル]]参照
===== リレーション =====
一対多、多対一、一対一リレーションをサポート。
artistテーブルはmusicテーブルに対して一対多リレーション、musicテーブルのartist_idが外部キーとする。
1側のエンティティ
@Entity
@Table(name="artist")
public class Artist {
@Id
@GeneratedValue
public long id;
public String name;
// 一対多リレーション(外部キーは相手が持っている)
@OneToMany(mappedBy="artist") // 相手側がartistという名前でArtist型プロパティを持っている必要がある
public List musicList;
}
多側のエンティティ
@Entity
@Table(name="music") // テーブル名=クラス名なので省略可(ただしDBがUNIX系OS上のMySQLは大文字小文字を区別するので設定が必要)
public class Music {
@Id
@GeneratedValue
@Column(name="id") // カラム名=フィールド名なので省略可
public long id;
@Column(name="name") // カラム名=フィールド名なので省略可
public String name;
@Column(name="artist_id") // カラム名=フィールド名でないので省略不可
public long artistId;
// 多対一リレーション
@ManyToOne
@JoinColumn(name="artist_id", referencedColumnName="id") // referencedColumnNameは相手テーブルのprimary keyなので省略可
public Artist artist;
}
アノテーションはJPAのもの(javax.persistence)を使う。
呼び出し側
public class Main {
public static void main(String[] arg) {
// S2Container 作成
SingletonS2ContainerFactory.init();
JdbcManager db = SingletonS2Container.getComponent(JdbcManager.class);
// 一対多
Artist artist
= db.from(Artist.class)
.leftOuterJoin("musicList") // テーブル名ではなく@OneToManyを設定したプロパティ名を指定する
.where(new SimpleWhere().eq("name", "Perfume"))
.getSingleResult();
System.out.println(artist.name);
for (Music music: artist.musicList) {
System.out.println(music.name);
}
// 多対一
List allMusic
= db.from(Music.class)
.innerJoin("artist") // テーブル名ではなく@ManyToOneを設定したプロパティ名を指定する
.getResultList();
for (Music music: allMusic) {
System.out.println(music.name + " : " + music.artist.name);
}
}
}
===== OR条件クエリの作成 =====
ComplexWhereを使う
public class Main {
public static void main(String[] arg) {
// S2Container 作成
SingletonS2ContainerFactory.init();
JdbcManager db = SingletonS2Container.getComponent(JdbcManager.class);
List favoriteMusic
= db.from(Music.class)
.innerJoin("artist")
.where(new ComplexWhere()
.eq("artist.name", "Perfume")
.and(new ComplexWhere()
.eq("name", "ポリリズム")
.or()
.eq("name","チョコレイトディスコ")))
.getResultList();
for (Music music: favoriteMusic) {
System.out.println(music.name + " : " + music.artist.name);
}
}
}
生成クエリのwhere部分
(T2_.NAME = 'Perfume' and ((T1_.name = 'ポリリズム') or (T1_.name = 'チョコレイトディスコ')))
ComplexWhereのネストがない場合
List favoriteMusic
= db.from(Music.class)
.innerJoin("artist")
.where(new ComplexWhere()
.eq("artist.name", "Perfume")
.eq("name", "ポリリズム")
.or()
.eq("name","チョコレイトディスコ"))
.getResultList();
生成SQL
((T2_.NAME = 'Perfume' and T1_.name = 'ポリリズム') or (T1_.name = 'チョコレイトディスコ'))
===== 外部SQLファイルを使う =====
準備中
===== MySQLのユーザ変数を使う =====
以下のようなSQLを発行すると、同一トランザクション中のSQLで@hogeという変数にアクセスできる。外部ファイルSQL呼び出しで検索条件DTO作るのめんどくさい時に使える。ただし当然MySQL依存。
jdbcManager.updateBySql("SET @hoge = ?", String.class).params("ほげ?").execute();
トランザクション境界は、SAStrutsの場合、Actionクラスのメソッド、またはServiceクラスのメソッド単位になる(もう少し調べる…)
===== 多対多 =====
JPAには多対多(ManyToMany)が定義されているが、S2JDBC(S2 2.4.25時点)には実装されていないので、@OneToManyと@ManyToOneを組み合わせて作成する
CDというテーブルとMusicというテーブルがTrackというテーブルでリレーションされている多対多関連を考える。エンティティは以下のようになる。
@Entity
@Table(name="cd")
public class Cd {
@Id
@GeneratedValue
public long id;
public String name;
// 多対多用の中間テーブルとのリレーション
@OneToMany(mappedBy="cd")
public List
呼び出しコードは以下のようになる
Cd cd
= db.from(Cd.class)
.leftOuterJoin("trackList")
.innerJoin("trackList.music") // trackListの要素TrackクラスがMusic型プロパティmusicを持っている事
.where(new SimpleWhere().eq("name", "GAME"))
.getSingleResult();
System.out.println(cd.name);
for (Track track : cd.trackList) {
System.out.print(track.number);
System.out.println(track.music.name);
}
トラック番号のような付加的なデータを持たせるために、中間テーブルのエンティティを明示的に作成するようにしているらしい。