HibernateでMySQLのleft joinを実装しました。
通常行う場合はそんなに困らないのですが、many-to-manyやone-to-manyなどの関連性がないテーブルどうしをleft joinさせるにはかなりの工夫が必要です。
前提としてテーブルAとテーブルBのHibernateマッピングファイル(A.hbm.xml, B.hbm.xml)はあって、これに対するJavaBeansがあるものとします。下記がそのサンプルテーブル例です。NOT NULLなどはとりあえず書いただけで気にしないでください。また、hbm.xmlは書く気力がないので勘弁してください。
TABLE_A:
ID INT NOT NULL,
NAME VARCHAR(20) NOT NULL,
ACCESS_TIME DATE
TABLE_B:
ID INT NOT NULL,
EMAIL VARCHAR(256) NOT NULL
上記テーブルのBeanが下記の通り。
TableA.java:
public class TableA {
private String id;
private String name;
private Date accessTime;
// 以下setter, getter
}
TableB.java:
public class TableB {
private String id;
private String email;
// 以下setter, getter
}
ではどのように実装すればいいかと申しますと、HibernateのSessionクラスにあるcreateSQLQueryを利用します。このメソッドではほぼSQLを書くのと同じなのですが、上記テーブルにて実装する場合は下記のようなSQLを書きます。
String sql = "select" +
"a.ID as {a1}.id, a.NAME as {a1}.name,a.ACCESS_TIME as {a1}.accessTime," +
"b.EMAIL as {b1}.email" +
" from TABLE_A as a left join TABLE_B as b on " +
"a.ID=b.ID" +
" where a.NAME=:name" +
" order by a.ID";
Query query = Session.createSQLQuery(sql, new String[] {"a1", "b1"},
new Class[] {TableA.class, TableB.class});
query.setString("name", name);
List = query.list();
まあ結果などはさておき、上記のように書けばleft joinを実装できます。
ここで注意なのは、SQL内で書いているカラム名は実際のテーブルカラム名をかかなければならないことです。HibernateではJavaの変数名で書くのが通常ですが、この場合はSQLを書くので実カラム名でなければなりません。
では戻ってくるリストはどのようになっているかと申しますと、上記のリストを受け取ってループ処理をする例を下記に示します。
for (int i = 0; i < list.size(); i++) {
Object[] obj = (Object[])list.get(i);
TableA a = (TableA)obj[0];
TableB b = (TableB)obj[1];
// あとは何らかの処理が続く
}
このあたりはちょっと考えればわかりそうなところです。先のcreateSQLQueryでClass配列を渡しているので、その順序で配列に収められています。で、また注意なのが、left joinなのでTableBのオブジェクトがNULLで返ってくる場合もありますのでチェックする必要があります。
ここまで学習して実装するまで6時間近くかかってしまいました。
DBによってSQLの実装方法が異なる場合があるので、上記の方法をとってしまうとMySQL上では動くけど、DBが変わった場合再実装しなければならないというデメリットがあります。
できればDB設計する際にきちんとした関連を持たせた設計をしたほうがいいと思います...
Hibernateの日本語ドキュメントが少なすぎで大変です...
