Hibernatにはいろいろな検索機能がありますが「Exampleによるクエリ」というのがあります。これは与えられたモデル(エンティティ)のプロパティにマッチするレコードを返す機能です。具体的には Item example = new Item(); example.setItemCode("C003"); <- アイテムコードのカラムが「C003」のモノ List list = dao.findByExample(example); <-合致するモノをDBから検索してListで返却 こんな感じです。アイテムコードが「C003」となっているレコードを取得することができます。便利ですね。 準備 †実際にやってみます。 テーブルと対応するJavaBeans? †
DAO †
やってみる †DAOの単体テストクラスを作って、その中で実際に検索を行います。DAOの単体テストクラスはSpring謹製のAbstractTransactionalDataSourceSpringContextTests?を継承したクラスとして作成します*1。 データのセットアップ †tableには以下のようなデータが入っています。
単体テストクラス †public class ItemDAOTestWithSpring extends AbstractTransactionalDataSourceSpringContextTests { public void testFindByExample() { logger.debug("testFindByExample() - start"); Item example = new Item(); example.setItemCode("C003"); example.setInitialPrice(202.5); List list = dao.findByExample(example); logger.debug("結果は " + list.size() + " 件でした"); Iterator iterator = list.iterator(); while (iterator.hasNext()) { Item element = (Item) iterator.next(); logger.debug(element); } logger.debug("testFindByExample() - end"); } .....あとはいろいろ省略 } 検索結果 †上の検索結果ですが、検索条件は「ITEM_CODE='C003' and INITIAL_PRICE=202.5」ということで 結果は 1 件でした nu.mine.kino.entity.webdb1.Item@d5c0f9[id=23,code=C003,Name=商品21_01,price=202.5] となります。 いろいろな検索条件 †0を除く †先の検索条件を Item example = new Item(); example.setItemCode("C003"); // example.setInitialPrice(202.5); List list = dao.findByExample(example); と変更します。検索条件は「ITEM_CODE='C003'」ということで、
がヒットしそうですが、検索結果は
の1件のみになります。これはこのテーブルのINITIAL_PRICEのデフォルト値がdefault '0' であるため、自動的に example.setInitialPrice?(0);がセットされて検索されるからです。 さて Item example = new Item(); example.setItemCode("C003"); List list = dao.findByExample(example); としたら「ITEM_CODE='C003'」のレコードがすべて返却されるのが感覚に合ってる気がします。そのためには「値をセットしなかった結果デフォルト値になってしまったカラムは検索条件から除く」としたいわけですが、そのようなやり方はさがしても見つかりませんでした。ただ、今回のように「0とセットされたカラムは検索条件から除く」ということはできます。それにはDAO内の DetachedCriteria dc = DetachedCriteria.forClass(Item.class); List results = getHibernateTemplate().findByCriteria(dc); return results; を DetachedCriteria dc = DetachedCriteria.forClass(Item.class); dc.add(Example.create(instance).excludeZeroes()); <-追加。 List results = getHibernateTemplate().findByCriteria(dc); return results; とします。この設定をしておくと、0とセットされたカラムを検索条件から除外するため結果的に「ITEM_CODE='C003'」だけが検索条件としてセットされます。結果は想定通り 結果は 3 件でした nu.mine.kino.entity.webdb1.Item@d5c0f9[id=21,code=C003,Name=商品21,price=505.5] nu.mine.kino.entity.webdb1.Item@1701bdc[id=23,code=C003,Name=商品21_01,price=202.5] nu.mine.kino.entity.webdb1.Item@1353249[id=25,code=C003,Name=商品21_02,price=0.0] となりました。ただこれだと、ホントにデータが0のレコードを検索することができないですね。 あるカラムだけ検索条件から除く †DAOで以下のように設定します。 DetachedCriteria dc = DetachedCriteria.forClass(Item.class); dc.add(Example.create(instance).excludeProperty("initialPrice")); List results = getHibernateTemplate().findByCriteria(dc); return results; こうしておくと、initialPrice フィールドは検索条件から除外されます。従って、 Item example = new Item(); example.setItemCode("C003"); example.setInitialPrice(100000.0); <-除外されたカラム List list = dao.findByExample(example); などとしても検索結果は 結果は 3 件でした nu.mine.kino.entity.webdb1.Item@d5c0f9[id=21,code=C003,Name=商品21,price=505.5] nu.mine.kino.entity.webdb1.Item@1701bdc[id=23,code=C003,Name=商品21_01,price=202.5] nu.mine.kino.entity.webdb1.Item@1353249[id=25,code=C003,Name=商品21_02,price=0.0] となります。initialPriceは正しく小文字で始めないとダメみたいですね。 そもそも、識別子は除外される。 †キーやバージョンのプロパティなどは検索条件から除外されるみたいです。 Item example = new Item(); example.setItemId(1); <-適当な値 example.setVersion(100); <-適当な値 example.setItemCode("C003"); List list = dao.findByExample(example); としても3件ヒットしました。また、nullやがセットされているカラムも除外されていますね。nameなどはそれにあたります。デフォルト値がありますががセットされるから、検索条件としては除外されています。 部分一致とか †次にNameカラムでいろいろ試してみます。DAOは DetachedCriteria dc = DetachedCriteria.forClass(Item.class); dc.add(Example.create(instance).excludeZeroes()); List results = getHibernateTemplate().findByCriteria(dc); とします。再掲ですがデータは
でした。 まずは完全一致から。 Item example = new Item(); example.setName("商品21"); List list = dao.findByExample(example); と実行すると完全一致のため
がヒットします。 結果は 1 件でした nu.mine.kino.entity.webdb1.Item@1701bdc[id=21,code=C003,Name=商品21,price=505.5] 部分一致させるためにはDAO内で部分一致を有効にする必要があります。以下のようにセットします。 DetachedCriteria dc = DetachedCriteria.forClass(Item.class); dc.add(Example.create(instance).excludeZeroes().enableLike()); <-enableLikeを追加 List results = getHibernateTemplate().findByCriteria(dc); 検索側も example.setName("商品21%"); とすることで部分一致検索となります。 結果は 3 件でした nu.mine.kino.entity.webdb1.Item@1579a30[id=21,code=C003,Name=商品21,price=505.5] nu.mine.kino.entity.webdb1.Item@4bfe6b[id=23,code=C003,Name=商品21_01,price=202.5] nu.mine.kino.entity.webdb1.Item@12c5431[id=25,code=C003,Name=商品21_02,price=0.0] と検索結果は3件になりました。 参考リンク †
この記事は 現在のアクセス:14450 |