Javaの道 Javaに関する
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道 >  掲示板 >  掲示板(jdbcManagerの可変条件式について)
閲覧数:2554
掲示板(jdbcManagerの可変条件式について)
名前
匿名
題名 jdbcManagerの可変条件式について
質問内容

質問を評価する
(0ポイント)
こんにちは。S2JDBCでのSQL条件式を作っているのですが、何とも汚いソースとなっており、指摘いただければと思い、投稿します。

下記のようにWhere句以降、パラメータのNullによって条件に含める、含めないといったものが、よくあると思うのですが、このように指定しないと組めないものでしょうか?

下記は単一テーブルに対してであり、Seasarのリファレンスページを見る限り、「SimpleWhere」を使ったもので実現できそうですが、INNER JOINなど複数テーブル結合文となると更にややこしくなりそうで、シンプルにSQL文をpreparestatement方式で実行できる形にしたいと思って、下記の様なソースになっています。
(動作自体は正常に動きますが・・汚い・・)

特に下記のこの部分が何とかならないものかと悩んでいます。

results = this.jdbcManager.selectBySql(BeanMap.class, sql, "1個目", "2個目","3個目", "4個目").getResultList();

良い方法がありましたら、指摘頂ければありがたいです。
よろしくお願いします。
質問日時 2013-04-02 03:54:49
名前
匿名
回答内容

回答を評価する
(0ポイント)
以下、汚いソースです。。

public List<UserMst> userSearch(String username, String usermail, String pref, String role) {
    List<UserMst> lt = new ArrayList<UserMst>();

    // 条件チェック
    List<LabelValueBean> cond = new ArrayList<LabelValueBean>();
    if (StringUtilz.isStr(username)) {
        cond.add(new LabelValueBean("username", "%"+username+"%"));
    }
    if (StringUtilz.isStr(usermail)) {
        cond.add(new LabelValueBean("mail", usermail));
    }
    if (StringUtilz.isStr(pref) && !"全国".equals(pref)) {
        cond.add(new LabelValueBean("pref", pref));
    }
    if (StringUtilz.isStr(role) && !"2".equals(role)) {
        cond.add(new LabelValueBean("role", role));
    }
    
    // SQL組立
    StringBuffer sql = new StringBuffer();
    sql.append("SELECT * FROM user_mst");
    for (int i = 0; i < cond.size(); i++) {
        LabelValueBean bn = cond.get(i);
        if (i == 0) {
            sql.append(" where ");
        } else {
            sql.append(" and ");
        }
        
        if (bn.getLabel().equals("username")) {
            sql.append("username like ? ");
        } else {
            sql.append(bn.getLabel()+" = ? ");
        }
    }
    sql.append(" order by role, yubin, username");
    
    // 一覧取得
    List<BeanMap> results;
    if (cond.size() == 4) {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString(), cond.get(0).getValue(), cond.get(1).getValue(), cond.get(2).getValue(), cond.get(3).getValue()).getResultList();
    } else if(cond.size() == 3) {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString(), cond.get(0).getValue(), cond.get(1).getValue(), cond.get(2).getValue()).getResultList();
    } else if(cond.size() == 2) {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString(), cond.get(0).getValue(), cond.get(1).getValue()).getResultList();
    } else if(cond.size() == 1) {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString(), cond.get(0).getValue()).getResultList();
    } else {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString()).getResultList();
    }

    for (int i = 0; i < results.size(); i++) {
        BeanMap bn = results.get(i);
        UserMst mt = new UserMst();
        mt.setUserid(bn.get("userid").toString());
        mt.setMail(bn.get("mail").toString());
        mt.setUsername(bn.get("username").toString());
        lt.add(mt);
    }
    return lt;
}
回答日時 2013-04-02 03:55:49
名前
匿名
回答内容

回答を評価する
(0ポイント)
S2は好みの問題で余り使わないのですが、
selectBySqlの第3引数は可変長引数ではないですか?

であれば、SQL組み立て前にパラメータ取り置き用に
ArrayList<Object>等を作って、

selectBySql(BeanMap.class,sql,paramList.toArray());

などではいかがでしょうか。
SQL組み立てと同タイミングでparamListに値を追加する
ことでselectBySql一行で、可変個数のパラメータに
対応できるのではないでしょうか。

(※試さないで書いてるのでうまくいかなかったらすみません)
回答日時 2013-04-02 10:47:42
名前
匿名
回答内容

回答を評価する
(0ポイント)
ありがとうございます。

確かに可変式なのですが、Listを指定してもout of Indexとエラーになります(空のList<Object>)。

Jd-clipseが正しく機能せず、動作部まで追えていません。。

<T> SqlSelect<T> selectBySql(Class<T> baseClass, String sql, Object... params);
回答日時 2013-04-02 15:06:33
名前
匿名
回答内容

回答を評価する
(0ポイント)
sql内にあるプレースホルダと同数、渡ってないんじゃない
の?
発行直前が想定通りか見てみたら。

ループではStringbuilderではなくListに溜めて、最後にjoinす
る。
区切りに何を指定するかというようなのを考えなくていいか
ら。
" where " + StringUtils.join(ary, " and ")みたいに。

また、DB周りはそこだけでクラスを分けておく方がいい。
回答日時 2013-04-02 20:25:28
名前
匿名
回答内容

回答を評価する
(0ポイント)
2つ上の者です。
分かりにくくてすみません。
リストではなくList.toArrayで配列にして渡しても駄目ですか?
回答日時 2013-04-02 20:27:23
名前
匿名
回答内容

回答を評価する
(0ポイント)
プレースホルダ0のときに配列渡しちゃいけない仕様なんだと
したら、それだけ条件分岐すりゃいい。
回答日時 2013-04-02 20:27:44
名前
匿名
回答内容

回答を評価する
(0ポイント)
うーん
ざっくり、S2周りのソース見た限りでは長さ0の配列でもエラー出なさそうだけど

○JdbcManagerImpl.java
http://www.seasar.org/source/browse/s2dao/trunk/slim-
dao/src/main/java/org/seasar/dao/manager/JdbcManagerImpl.java?view=markup&sortby=rev&sortdir=down

○SqlSelectImpl
http://www.seasar.org/source/browse/s2dao/trunk/slim-
dao/src/main/java/org/seasar/dao/query/SqlSelectImpl.java?view=markup&sortby=rev&sortdir=down

ListオブジェクトをそのままselectBySqlの第3引数に渡したりしてないですよね?
回答日時 2013-04-02 20:44:26
名前
匿名
回答内容

回答を評価する
(0ポイント)
質問者です。

ありがとうございます。
確認してみたのですが、やはりだめでした。

>プレースホルダ0のときに配列渡しちゃいけない仕様なんだと
>したら、それだけ条件分岐すりゃいい。

おっしゃる通り、この分岐は必要ですがこれはWhere句の無いSQLとなります。

また、1個以上条件が含まれても、out of Indexでエラーとなります。
内部的なキャストエラーなのか・・
回答日時 2013-04-02 20:48:38
名前
匿名
回答内容

回答を評価する
(0ポイント)
質問者です。

ありがとうございます。
解決しました。

下記のように若干ソースが綺麗になりました。
 StringUtils.joinをするとListが3つも必要となってしまう為、このままにしました。すみません。

あと、パラメータ格納のListですが、Objectにしないと正常に動かないようです。
Stringでやってみましたがだめでした。
(toArray()も必要です)

色々ありがとうございました。

public List<UserMst> userSearch(String username, String usermail, String pref, String role) {
    List<UserMst> lt = new ArrayList<UserMst>();

    // SQL組立
    StringBuffer sql = new StringBuffer();
    sql.append("SELECT * FROM user_mst");
    List<Object> cond = new ArrayList<Object>();
    if (StringUtilz.isStr(username)) {
        sql.append(" where username like ? ");
        cond.add("%"+username+"%");
    }
    if (StringUtilz.isStr(usermail)) {
        if (cond.size() < 1) {
            sql.append(" where ");
        } else {
            sql.append(" and ");
        }
        sql.append(" mail = ? ");
        cond.add(usermail);
    }
    if (StringUtilz.isStr(pref) && !"全国".equals(pref)) {
        if (cond.size() < 1) {
            sql.append(" where ");
        } else {
            sql.append(" and ");
        }
        sql.append(" pref = ? ");
        cond.add(pref);
    }
    if (StringUtilz.isStr(role) && !"2".equals(role)) {
        if (cond.size() < 1) {
            sql.append(" where ");
        } else {
            sql.append(" and ");
        }
        sql.append(" role = ? ");
        cond.add(role);
    }
    sql.append(" order by role, yubin, username");
    
    // 一覧取得
    List<BeanMap> results;
    if (cond.size() > 0) {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString(), cond.toArray()).getResultList();
    } else {
        results = this.jdbcManager.selectBySql(BeanMap.class, sql.toString()).getResultList();
    }

    for (int i = 0; i < results.size(); i++) {
        BeanMap bn = results.get(i);
        UserMst mt = new UserMst();
        mt.setUserid(bn.get("userid").toString());
        mt.setMail(bn.get("mail").toString());
        mt.setUsername(bn.get("username").toString());
    }
}
回答日時 2013-04-03 01:17:29
名前
匿名
回答内容

回答を評価する
(0ポイント)
intやらDateやらもあるんだから、もちろんObjectだよ。
回答日時 2013-04-03 06:42:33
名前
匿名
回答内容

回答を評価する
(0ポイント)
ん?

なぜプログラム中でSQLを組むの?
http://s2container.seasar.org/2.4/ja/s2jdbc_manager_
sqlfile.html

回答日時 2013-04-03 14:49:08

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。



このページのトップへ
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道_CopyrightJavaの道