NetBeans6.8 BetaでJPA2.0を試してみる。 - その5

  昨日下書きの途中まで書いていた内容に関する事をずばりid:trygunさんがこちらにて指摘されています。

  そうなんです。JPA2.0のCriteriaでは「or」の使い方が特殊というか、SQLやJPQL的な書き方と違うようです。
ちなみに自分は最初ハマりましたw

以下に出てくるCriteriaの文に関しては前提として下記の変数が定義されていると想定しておいて下さい。

        CriteriaBuilder qb = em.getCriteriaBuilder();
        CriteriaQuery<Customer> cq = qb.createQuery(Customer.class);
        Root<Customer> r = cq.from(Customer.class);

orの使い方

  例えばSQLで下記のような文を書きたい場合

    SELECT
        * 
    FROM
        CUSTOMER
    WHERE
        customer_id = 1 OR
        customer_id = 2

  JPAのCriteriaでは

    cq.select(r).
        where(qb.equal(r.get(Customer_.customerId), 2),
              qb.or(qb.equal(r.get(Customer_.customerId), 1)))

上記のように書いてしまいそうですが、これだと期待した結果は得られません。

上記を実行した場合に発行されるSQLは下記のようになります(SELECT句は*で簡略しています)

    SELECT
        *
    FROM
        CUSTOMER
    WHERE 
       ((CUSTOMER_ID = 2) AND (CUSTOMER_ID = 1)) --普通にANDでつなげられる。

なので、期待するSQLを発行する場合は下記のようにしなければいけないようです。

        cq.select(r).
                where(qb.or(qb.equal(r.get(Customer_.customerId), 1),
                            qb.equal(r.get(Customer_.customerId), 2)));

つまりSQLでいうところの「or」で判定したい部分をCriteriaBuilderのorメソッドの引数に指定するということにでしょうか。また、CriteriaBuilderにはandというメソッドがあり、こちらはorの中などでandでつなげたい場合に使用するもようです。
なので、id:trygunさんがこちらの最後に書いたSQL(where A and(B and C or D and E))をJPA2.0のタイプセーフなCriteriaで記述する場合は下記のようになるっぽいです。

    where(qb.equal(r.get(Customer_.city), "New York"),
              qb.and(qb.or(qb.and(qb.equal(r.get(Customer_.addressline1), "El Camino"),
                             qb.equal(r.get(Customer_.name), "Foo")),
                      qb.and(qb.equal(r.get(Customer_.addressline1), "4th Street"),
                             qb.equal(r.get(Customer_.name), "Bar")))));

いや〜、どうでしょうか(;´Д`)。なんか「 ) 」がたくさんですwww。ちなみにこの単純なクエリの作成に自分は20分くらいかかりましたwww。
「あれ?この「 ) 」ってどこで閉じられるやつだっけ??」とか、「あぁぁ、なんかよくわかんないけどコンパイルエラーが・・・」とか、実行してコンソールに吐き出されたSQLが意味不明だったりとかwww

ただ、自分は英語が読めないのに無理やりJPA2.0の仕様書読んでいるのと、数少ないサンプルを見ながら試しているので使い方を間違っている可能性もあります。よって、このエントリーだけ見て「JPA2.0使えね」と思われるとJSRの中の人が悲しむ可能性大ですwww

次回はJOINとかのエントリーを書いていこうかと思います。