menu
書いてる野郎
orebike@gmail.com
1:N 関係の結合を表すにはどうするか問題。
MyBatis は単に SQL の結果をどのようにオブジェクトに割り当てるかしか考えていないので、 多段結合や N:N には関知しない。
しかし 1:N の関係は結果が逆転する処理なのでどのように記述できるか興味深い。 S2JDBC ではこのへんの詰替えを非常に巧妙に行っていた。しかしページング処理がうまく動かないとかの問題もあった。
これの問題は SELECT したレコード数と実際の結果 List の size が一致しないからである。
N:1 の関係性のマッピング。
親子関係があるテーブルで子から見て親を含むような結合をした結果を格納したい場合どうするか?
このような Domain を考える
Mapper で使う Domain には必ず引数の無いコンストラクタが必要になる。
public class Hoge{ private Long hogeId; private List<Piyo> piyoList; private String name; private String memo; // 以下 引数無しコンストラクタ // getter setter }
public class Piyo{ private Long piyoId; private Long hogeId; private String name; private String memo; // 以下 引数無しコンストラクタ // getter setter }
Hoge が Piyo を複数個保持しているような関係。よくありげ
この SQL はこんな感じになる。
<select id="findByIdWithPiyo" resultMap="hogeResultMapWithPiyo"> SELECT h.hoge_id AS hoge_id, h.piyo_id AS piyo_id, h.name AS hoge_name, h.memo AS hoge_memo, p.name AS piyo_name, p.memo AS piyo_memo FROM hoge h LEFT JOIN piyo p ON h.hoge_id = p.hoge_id WHERE p.hoge_id = #{hogeId} AND p.deleted = 0 ; </select>
1:N の関係にて piyo を JOIN しているので結果レコード数は piyo のレコード数に従う。
この結果に対してこのようにマッピングする
<resultMap id="hogeResultMapWithPiyo" type="com.unko.domain.Hoge"> <constructor> <idArg column="hoge_id" javaType="long" /> </constructor> <result property="name" column="hoge_name"/> <result property="memo" column="hoge_memo"/> <collection property="piyoList" ofType="com.unko.domain.Piyo"> <id property="piyoId" column="piyo_id"/> <result property="name" column="piyo_name"/> <result property="memo" column="piyo_memo"/> </collection> </resultMap>
まず constructor
という指定をしている。
ここは単純に com.unko.domain.Hoge
のクラスが持つコンストラクタをどう使うのかを指定している。
この場合だと hoge_id
という1つの値を取るコンストラクタを用意しておくということ。
次は今まで通りマッピング指定していく
次にリレーションで引っ張ってきた値に対してもマッピングする。
その時は association
というタグを指定する property にはそれを格納するための setter を指定して javaType にはその型を指定する。
中は通常の mapping と同じ様に書く。
これで実行すると、hoge はもちろんその中の piyo も生成されて setPiyo される。
これはそのまま One To One であっても成立する。