読者です 読者をやめる 読者になる 読者になる

S2Daoのメモ

seasar

group@PostgreSQL

PostgreSQLではgroupというリレーション名は予約語になっているらしいです。

で、S2Daoで、N:1マッピングを

@Bean(table = "my_user")
public class User {
  @Relation(relationNo = 0, relationKey = "gid:id")
  Group getGroup() { ... }
}

@Bean(table = "my_group")
public class Group {
}

などとした場合、自動生成されるSQLは、

SELECT my_user.password, my_user.id, my_user.loginid, my_user.name, group.id AS id_0, group.name AS name_0
 FROM my_user
 LEFT OUTER JOIN my_group group ON my_user.groupid = group.id

となります。

そう。よく見るとmy_groupのエイリアス名が「group」となっています。
実行すると

Throwable:org.seasar.framework.exception.SQLRuntimeException: [ESSR0071]SQLで例外が発生しました。理由はorg.postgresql.util.PSQLException: ERROR: syntax error at or near "group"

とエラーになります。

このエイリアス名はgetterメソッド名に依存するので、たとえば

 getGroup() → getHogeGroup()

などとすると、

SELECT my_user.password, my_user.id, my_user.loginid, my_user.name, hogeGroup.id AS id_0, hogeGroup.name AS name_0
 FROM my_user
 LEFT OUTER JOIN my_group hogeGroup ON my_user.groupid = hogeGroup.id

となります。他のところのつじつまを合わせればSQL上はエラーとはなりません。

が、面倒くさい...。

単にGroupという概念名は使っちゃいかんということですかね。
この場合はUserGroupとリネームしてもいいですが、好みではないのでちょっとムムムです。

2005-10-06 - 豆無日記でも全く同じことではまってましたね...。

交差エンティティとBeanの構成

よくある交差エンティティの例として

CREATE TABLE tbl_a (
    id  SERIAL PRIMARY KEY,
    value text
);
CREATE TABLE tbl_a_b (
    id  SERIAL PRIMARY KEY,
    aid INTEGER,
    bid INTEGER
);
CREATE TABLE tbl_b (
    id  SERIAL PRIMARY KEY,
    value text
);

というテーブルがあったとします。
で、BeanとDaoをどうやって実装しようかと。

前提として、基本的にtbl_a:tbl_b=N:1とし、N:Mなどの拡張は今のところJava実装レベルでは考慮しないことにします。(DBレベルでは交差エンティティを導入している時点である程度考慮していることになりますね。)

A案: view
CREATE VIEW view_a
AS
 SELECT a.*, ab.bid FROM tbl_a a
 LEFT JOIN tbl_a_b ab ON a.id = ab.aid

と、tbl_a側にbidが含まれるようなviewを作っておいて

@Bean(table = "view_a") // ←viewを指定!!
class BeanA {
    private long id;
    private String text;
    private BeanB b;

    @Relation(relationNo = 0, relationKey = "bid:id")
    BeanB getB() { ... }
}
@Bean(table = "tbl_b")
class BeanB {
    private long id;
    private String text;
}

とする案。

B案: SQLファイル

ふつうに

@Bean(table = "tbl_a")
class BeanA {
    private long id;
    private String text;
    private BeanB b;

    @Relation(relationNo = 0, relationKey = "bid:id")
    BeanB getB() { ... }
}
@Bean(table = "tbl_b")
class BeanB {
    private long id;
    private String text;
}

としておいて、SQLファイルで

 SELECT a.*, ab.bid, b.id AS id_0, b.text AS text_0 FROM tbl_a a
 LEFT JOIN tbl_a_b ab ON a.id = ab.aid
 LEFT JOIN tbl_b b ON ab.id = b.id

と指定する案。


どっちがいいんでしょうかね。

単にfindするだけであればどっちの案でも構わないんですが、今のところわかってるのはS2DaoTestCaseでreadXls()したDataSetと、取得したBeanのListを比較するときに

org.seasar.extension.jdbc.ColumnNotFoundRuntimeException: [ESSR0068]テーブル(S2DaoBean)のカラム(ID_0)が見つかりません
	at org.seasar.extension.dataset.impl.DataTableImpl.getColumn(DataTableImpl.java:145)
	at org.seasar.extension.dataset.impl.DataRowImpl.getValue(DataRowImpl.java:72)
	〜(省略)〜

のようにうまいことマッチングできないみたいです。S2DaoTestCaseの使い方が悪いだけかもしれません。

それにINSERTやUPDATEのときに楽なのはどっちなのか?結局そのときは別のDaoメソッドを実装するのか、などがわかってません。

要継続調査。


結局N:1しかないのなら、交差エンティティを使わずに最初からA案のview_aのようなtbl_aを定義すればいいという気がしますが、迷ったら交差エンティティにすべしという漢塾(オトコジュク)方式の場合はどう解決しているんでしょうか...。