[Seasar-user:16112] Re: [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい
Shotaro Tsubouchi
[E-MAIL ADDRESS DELETED]
2008年 10月 26日 (日) 06:27:36 JST
自己レスです。
基本的に id でしか結合されない事を考えると、
追加の結合条件の存在意義って何だろう?と思いました。
select T1_.*, T3_.*
from FOO T1_,
BAA T2_,
BAA T3_,
where T3_.FOO_ID = T1_.ID
and T2_.FOO_ID = T1_.ID
and T2_.ID = 1
ベタだとこう書くものを、結合をわかりやすく
select T1_.*, T3_.*
from FOO T1_
inner join BAA T2_ on T2_.FOO_ID = T1_.ID
inner join BAA T3_ on T3_.FOO_ID = T1_.ID
where T2_.ID = 1
こう書けるようにしているに過ぎないのであって、
そう考えると T2_ に対する条件なのだから、
select T1_.*, T3_.*
from FOO T1_
inner join BAA T2_ on T2_.FOO_ID = T1_.ID and T2_.ID = 1
inner join BAA T3_ on T3_.FOO_ID = T1_.ID
こう書く方が自然なのではないでしょうか。
これであれば、
select() // jdbcManager.from(Foo.class)
.innerJoin(baaList(), false)
.innerJoin(baaList())
.where(eq(baaList(2).id(), 1))
.getResultList();
こんな若干トリッキーな指定をしなくても、
select() // jdbcManager.from(Foo.class)
.innerJoin(baaList(), false, eq(baaList().id(), 1))
.innerJoin(baaList())
.getResultList();
で済んで、フェッチしない結合の重複を許すだけで良いですし。
なにげに、結合条件の追加の例自体、そういう使われ方だったりしてますw
http://s2container.seasar.org/2.4/ja/s2jdbc_manager_auto.html#%E7%B5%90%E5%90%88%E6%9D%A1%E4%BB%B6%E3%81%AE%E8%BF%BD%E5%8A%A0JOIN
Shotaro Tsubouchi さんは書きました:
> ショータローこと坪内です。
>
> いやはや、こちらこそ寝ぼけまなこであまり考えずに書いてました。。
>
>> と JOIN ON 〜 で条件を指定するのではなく,
>> WHERE で指定すべきかと.
>
> タイプセーフな書き方で何とか、とか考えているうちにこうなってました。
> 確かに本来は WHERE で指定するものなのでしょうが、
> スマートに書けなさそうだったので。。
>
>> このケースで片方が leftOuterJoin なのは作為的な
>> 気がします.(^^;
>
> このケースだと leftOuterJoin である必要は全然無かったですね。。
> 本来的に発行されるべきクエリーは、副問い合わせの必要はなく、
>
> select T1_.*, T3_.*
> from FOO T1_
> inner join BAA T2_ on T2_.FOO_ID = T1_.ID
> inner join BAA T3_ on T3_.FOO_ID = T1_.ID
> where T2_.ID = 1
>
> こうではないかと思います。と考えると、
>
> ・フェッチしない結合は重複を許す
> ・WHERE で JOIN の番号を指定可能にする
>
> ができれば良くて、
>
> select() // jdbcManager.from(Foo.class)
> .innerJoin(baaList(), false)
> .innerJoin(baaList())
> .where(eq(baaList(2).baaId(), 1))
> .getResultList();
>
> みたいな感じで行けるようになったりしないですかね?
> かなり希望的観測ですが。
>
>
> Koichi Kobayashi さんは書きました:
>> 小林 (koichik) です.
>>
>> 出かける支度中で慌て気味なので変なこと
>> 書いてるかもしれませんがご容赦ください.
>>
>> Date: Sat, 25 Oct 2008 09:53:23 +0900
>> From: Shotaro Tsubouchi <[E-MAIL ADDRESS DELETED]>
>> To: [E-MAIL ADDRESS DELETED]
>> Subject: [Seasar-user:16109] [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい
>>
>>> 親子関係にある Entity、Foo と Baa において、
>>> ID が 1 の Baa を持っている Foo を取得し、
>>> その Foo 毎に関連する Baa も取得したい場合、
>> ここで「ID が 1 の Baa を持っている」は
>> 結合条件ではなく選択条件なので,
>>
>>> select() // jdbcManager.from(Foo.class)
>>> .innerJoin(baaList(), false, eq(baaList().baaId(), 1))
>>> .leftOuterJoin(baaList())
>>> .getResultList();
>> と JOIN ON 〜 で条件を指定するのではなく,
>> WHERE で指定すべきかと.
>>
>> となると EXISTS または IN で相関福問い合わせを
>> 使うことになりますが,S2JDBC の SimpleWhere は
>> サポートしていないので,where(String, Object...) を
>> 使うことになってしまいます.
>>
>> 相関福問い合わせは SQL だと
>>
>> 〜 where exists (select * from BAA where BAA_ID = ? and FOO_ID = T1_.FOO_ID)
>>
>> みたいになります.
>> # この例は多対多関連なので本当は FOO_ID なんて
>> # ないのかもしれませんが.
>>
>> ここで T1_ は主問い合わせの Foo のエイリアスで,
>> S2JDBC が割り振るものです.
>> S2JDBC は where(String, Object...) に渡された
>> 文字列にこのエイリアスを自動的に割り振るので
>> T1_ は省略できます.
>>
>> select() // jdbcManager.from(Foo.class)
>> .innerJoin(baaList())
>> .getResultList();
>> .where("exists (select * from BAA where BAA_ID = ? and FOO_ID = fooId", 1)
>> .getResultList();
>>
>> のようになるかと思うのですが,試してないので
>> 怪しいかも.
>> カラム名とプロパティ名が入り乱れて気持ち悪い...
>>
>>
>>> ひとまず、AutoSelectImpl の 774 行目をコメントアウトして
>>> 例外を無視してみたところ、想定していたクエリーを発行できました。
>>> 結合条件の重複チェックが、innerJoin と leftOuterJoin で
>>> 分かれていれれば良いんですかね?
>> このケースで片方が leftOuterJoin なのは作為的な
>> 気がします.(^^;
>>
>> 制約をゆるめるなら,フェッチしない結合は重複を
>> 許すということが考えられますが,フェッチしない
>> ということは選択条件のためということになり,
>> それなら WHERE 句で頑張るのが筋かなと.
>> そのためには相関福問い合わせのサポートを向上する
>> 必要があって悩ましいですが.
>>
>>
>
Seasar-user メーリングリストの案内