Top / Hibernate / マッピング定義について / いろいろな検索方法

データは以下のようになっているとします。

mysql> select * from Samples.CUSTOMER;
+----+-----------+---------+
| ID | NAME      | USER_ID |
+----+-----------+---------+
|  1 | CUSTOMER1 |       1 |
|  2 | CUSTOMER2 |    NULL |
|  3 | CUSTOMER3 |       3 |
|  4 | CUSTOMER4 |       2 |
|  5 | CUSTOMER5 |       2 |
+----+-----------+---------+
5 rows in set (0.00 sec)

mysql> select * from Samples.USER;
+----+-------+
| ID | NAME  |
+----+-------+
|  1 | USER1 |
|  2 | USER2 |
|  3 | USER3 |
+----+-------+
3 rows in set (0.00 sec)

mysql>

HQLで検索する

通常通りやってみる

まずはHQLで検索してみます。

public static void main(String[] args) {
   DOMConfigurator.configure("log4j.xml");
   try {
     final SessionFactory sessionFactory = getSessionFactory();
     Session session = sessionFactory.openSession();
     Transaction tx = session.beginTransaction();

     Query query = session.createQuery("from Customer");
     List models = query.list();
     Iterator it = models.iterator();
     while (it.hasNext()) {
       System.out.println(it.next());
     }
     session.flush();
     session.close();

   } catch (Throwable e) {
     e.printStackTrace();
   }
}

結果は以下の通り。

org.hibernate.SQL - select customer0_.ID as ID1_, customer0_.USER_ID as USER2_1_, 
                    customer0_.NAME as NAME1_ from Samples.CUSTOMER customer0_
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@1d439fe[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@1e78c96[id=1,name=USER1]]
nu.mine.kino.entity.Customer@148f8c8[id=2,name=CUSTOMER2,担当者=<null>]
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@1c5466b[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@c2ee15[id=3,name=USER3]]
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@922804[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@1d0d45b[id=2,name=USER2]]
nu.mine.kino.entity.Customer@1815338[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@1d0d45b[id=2,name=USER2]]

CUSTOMERが全件検索されて、その後に関連つくUSERが検索されています。

結合をHQLでやる(from句で)

Joinをhbmの設定を利用してやってると、デフォルトではSQL一発ではなくCustomerごとにUserを取ってくる模様。これだとパフォーマンス的に悲惨になりそうなので、HQLでつなげてみました。

public static void main(String[] args) {
  DOMConfigurator.configure("log4j.xml");
  try {
    final SessionFactory sessionFactory = getSessionFactory();

    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    Query query = session
        .createQuery("from Customer as customer left join customer.user");
    List models = query.list();
    Iterator it = models.iterator();
    while (it.hasNext()) {
      Object element = it.next();
      Object[] objects = (Object[]) element;
      System.out.println(objects[0]);  // 明示的にjoinすると
      System.out.println(objects[1]);  // CustomerとUserの配列になる??
    }
    session.flush();
    session.close();
  } catch (Throwable e) {
    e.printStackTrace();
  }
}

結果は以下の通り。

org.hibernate.SQL - select customer0_.ID as ID1_0_, user1_.ID as ID0_1_,customer0_.USER_ID as USER2_1_0_,
                           customer0_.NAME as NAME1_0_,user1_.NAME as NAME0_1_
                           from Samples.CUSTOMER customer0_ left outer join Samples.USER user1_
                           on customer0_.USER_ID=user1_.ID
nu.mine.kino.entity.Customer@17e845a[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@1ba0f36[id=1,name=USER1]]
nu.mine.kino.entity.User@1ba0f36[id=1,name=USER1]
nu.mine.kino.entity.Customer@3caa4b[id=2,name=CUSTOMER2,担当者=<null>]
null
nu.mine.kino.entity.Customer@d0220c[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@6b496d[id=3,name=USER3]]
nu.mine.kino.entity.User@6b496d[id=3,name=USER3]
nu.mine.kino.entity.Customer@1a19458[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@1124746[id=2,name=USER2]]
nu.mine.kino.entity.User@1124746[id=2,name=USER2]
nu.mine.kino.entity.Customer@105691e[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@1124746[id=2,name=USER2]]
nu.mine.kino.entity.User@1124746[id=2,name=USER2]

SQL内でOuter Joinしてくれるようになりました。しかし戻りが配列になってるのがいかんですねぇ。

ちなみにleft joinを ただの joinと書くと内部結合になります。つまりUSER_IDがNULLのCUSTOMERは検索されません。

配列のところを改善する

先のクエリ

Query query = session
        .createQuery("from Customer as customer left join customer.user");

では返り値がCustomer,Userの配列(のリスト)となっていました。これをCustomerだけを返すようにするには以下のようにクエリを変更すればOKです。

Query query = session
        .createQuery("select customer from Customer as customer left join customer.user");

このようにselect [クラスのエイリアス名] とすれば、指定したクラスだけを返すことができます。結果は以下の通り。

org.hibernate.SQL - select customer0_.ID as ID1_, customer0_.USER_ID as USER2_1_, customer0_.NAME as NAME1_ 
                           from Samples.CUSTOMER customer0_ left outer join Samples.USER user1_ 
                           on customer0_.USER_ID=user1_.ID
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@1815338[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@16917ee[id=1,name=USER1]]
nu.mine.kino.entity.Customer@12368df[id=2,name=CUSTOMER2,担当者=<null>]
DEBUG org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@1ba0f36[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@1d0d45b[id=3,name=USER3]]
DEBUG org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@3caa4b[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@11db6bb[id=2,name=USER2]]
nu.mine.kino.entity.Customer@d0220c[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@11db6bb[id=2,name=USER2]]

確かに戻り値が配列ではなくなったのですが、selectがまた乱発されてしまった。。。うーん。

結合をHQLでやる(where句で)

次にwhere句で結合します。

Query query = session
 .createQuery("from Customer as customer,User as user where customer.user.id=user.id");

これの結果はCustomer,Userの配列です。

org.hibernate.SQL - select customer0_.ID as ID1_0_, user1_.ID as ID0_1_, customer0_.USER_ID as USER2_1_0_, 
                           customer0_.NAME as NAME1_0_, user1_.NAME as NAME0_1_ 
                           from Samples.CUSTOMER customer0_, Samples.USER user1_ 
                           where customer0_.USER_ID=user1_.ID
nu.mine.kino.entity.Customer@3caa4b[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@6b496d[id=1,name=USER1]]
nu.mine.kino.entity.Customer@1a19458[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@1124746[id=3,name=USER3]]
nu.mine.kino.entity.Customer@105691e[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@383118[id=2,name=USER2]]
nu.mine.kino.entity.Customer@11f23e5[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@383118[id=2,name=USER2]]

だんだんSQLみたいになってきました。

Criteriaで検索する

通常通りやってみる

次にCriteriaを使って検索します。

public static void main(String[] args) {
  DOMConfigurator.configure("log4j.xml");
  try {
    final SessionFactory sessionFactory = getSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    Criteria criteria = session.createCriteria(Customer.class);
    // criteria.setFetchMode("user", FetchMode.JOIN); <-フェッチの指定
    List models = criteria.list();
    Iterator it = models.iterator();
    while (it.hasNext()) {
      System.out.println(it.next());
    }
    session.flush();
    session.close();

  } catch (Throwable e) {
    e.printStackTrace();
  }
}

結果は以下の通り。

org.hibernate.SQL - select this_.ID as ID1_0_, this_.USER_ID as USER2_1_0_, 
                    this_.NAME as NAME1_0_ from Samples.CUSTOMER this_
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@32060c[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@1e1be92[id=1,name=USER1]]
nu.mine.kino.entity.Customer@1efb4be[id=2,name=CUSTOMER2,担当者=<null>]
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@435a3a[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@1860038[id=3,name=USER3]]
org.hibernate.SQL - select user0_.ID as ID0_0_, user0_.NAME as NAME0_0_ from Samples.USER user0_ where user0_.ID=?
nu.mine.kino.entity.Customer@1d8c528[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@1b33a0e[id=2,name=USER2]]
nu.mine.kino.entity.Customer@77eaf8[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@1b33a0e[id=2,name=USER2]]

やっぱりCUSTOMERが全件検索されて、その後に関連付くUSERが検索されています。

フェッチの指定をする

コメントアウトしていた

criteria.setFetchMode("user", FetchMode.JOIN); <-フェッチの指定

をアンコメントしてフェッチのモードを変更してやってみます。結果は以下の通り。

org.hibernate.SQL - select this_.ID as ID1_1_, this_.USER_ID as USER2_1_1_, 
                           this_.NAME as NAME1_1_, user2_.ID as ID0_0_, 
                           user2_.NAME as NAME0_0_ from Samples.CUSTOMER this_ 
                           left outer join Samples.USER user2_ on this_.USER_ID=user2_.ID
nu.mine.kino.entity.Customer@e35bb7[id=1,name=CUSTOMER1,担当者=nu.mine.kino.entity.User@1d8c528[id=1,name=USER1]]
nu.mine.kino.entity.Customer@9a8a68[id=2,name=CUSTOMER2,担当者=<null>]
nu.mine.kino.entity.Customer@1038de7[id=3,name=CUSTOMER3,担当者=nu.mine.kino.entity.User@1f4e571[id=3,name=USER3]]
nu.mine.kino.entity.Customer@183e7de[id=4,name=CUSTOMER4,担当者=nu.mine.kino.entity.User@5976c2[id=2,name=USER2]]
nu.mine.kino.entity.Customer@10fe2b9[id=5,name=CUSTOMER5,担当者=nu.mine.kino.entity.User@5976c2[id=2,name=USER2]]

あらかじめOuter Joinして検索してくれています。


この記事は

選択肢 投票
おもしろかった 0  
そうでもない 0  

Top / Hibernate / マッピング定義について / いろいろな検索方法

現在のアクセス:37269


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS