2011-01-26 7 views
11

1対多と多対1の関連付けを遅延ロードできますが、多対多の関連付けではできません。休止状態で多対多のコレクションを遅延ロードする方法はありますか?

私たちには、商人の住所がある都市があります。 商人は複数の住所を持つことができ、複数の商人は同じ住所を持つことができます。

我々は、getと商人をロードし、

Merchant merchant = (Merchant) hib_session.get(Merchant.class, id); 
System.out.println(merchant.getName()); 

それは我々がそれらを反復処理するまでのアドレスがロードされていない、大丈夫です。

しかし、我々は、商人のリストをロードする際

City city = (City) hib_session.get(City.class, city_name); 
for(Merchant merchant : city.getMerchants()) { 
    System.out.println(merchant.getName()); 
} 

我々はアドレスを取得していない場合でも、自動的に休止状態にそれらをロードします。

Here's an example of my problem.

マッピング:

<class name="Merchant" table="Merchants" lazy="true"> 
    <id name="id" 
    type="long" 
    column="id"> 
    <generator class="native"></generator> 
    </id> 
    <set name="addresses" table="AdressesMerchant" lazy="true"> 
    <key column="merchant_id"></key> 
    <many-to-many class="Adresses" column="address_id"/> 
    </set> 
</class> 

<class name="Address" table="Adresses" lazy="true"> 
    <id name="id" 
    type="long" 
    column="id"> 
    <generator class="native"></generator> 
    </id> 
    <set name="merchants" table="AdressesMerchant" lazy="true"> 
    <key column="adress_id"/> 
    <many-to-many column="merchant_id" class="Merchant"/> 
    </set> 
</class> 

任意のアイデア?

+1

奇妙に聞こえる。あなたはその行動を確認できますか?あなたのコレクションはどのようにマップされていますか? – Bozho

+0

@Bozhoクエリを記録することで動作を確認でき、Hibernateがアドレスをロードすることがわかります。私は質問にマッピングを追加しました。 – codea

+1

これは話題ではありませんが、inverseでマークされた多対多の関係の1つであってはなりませんか? – Ralph

答えて

-1

基準オブジェクトを使用して、FetchMode.EAGERを照会して使用することができます。

+0

OPは、他の関連するエンティティをロードしたくない**という状態でした。 – luksch

1

私が見つけた2つの修正点があります。簡単なのは、トランザクションを持つことです。 bussinessメソッドでトランザクションを開始すると、そのメソッドのライフサイクル内でいつでもこれらを遅延初期化することができます。あなたのトランザクションがコンテナ管理されている場合は、その方法で単純な@TransactionAttribute(TransactionAttributeType.REQUIRED)がこれを達成するのに十分です。別の方法は、Hibernate.initialize(object.getDesiredColletion())を使用することです。これもオブジェクトをフェッチしますが、トランザクションも必要です。

私の最後の解決策は、トランザクションがない場合です。このジェネリックメソッドは、基本的にあなたのcolletを取得し、setterメソッドを使用してそれらを親オブジェクトに設定します。このプロセスを改善するには、IDを渡さずに一般的に取得し、javaのセキュリティ設定を変更したくない場合は、コレクションを親オブジェクトに直接設定することができます(プライベートでも)。このコードを大きく減らすことができます。

public Object fetchCollections(Object parent, Long id, Class<?>... childs) { 

    logger.debug("Need to fetch " + (childs.length) + " collections"); 
    String fieldName = ""; 
    String query = ""; 
    for (int i = 0; i < childs.length; i++) { 
     logger.debug("Fetching colletion " + (i + 1) + " of " 
       + (childs.length)); 
     logger.debug("Collection type is " + childs[i].getSimpleName()); 

     fieldName = findFieldName(childs[i], parent.getClass()); 
     if (fieldName == null) { 
      logger.debug("Trying to search with parent class"); 
      logger.debug(parent.getClass().getSuperclass()); 
      fieldName = findFieldName(childs[i], parent.getClass() 
        .getSuperclass()); 

     } 
     logger.debug("Creating query"); 
     query = "from " + childs[i].getSimpleName() + " obj " + "where " 
     + " obj." + fieldName + ".id=" + id; 
     logger.debug("Query= " + query); 
     Set collection = new HashSet(em.createQuery(query).getResultList()); 
     setCollection(parent, collection, fieldName, childs[i]); 

    } 

    return parent; 

} 


private String findFieldName(Class parentClass, Class childClass) { 
    String fieldName = null; 
    boolean isCollection = false; 
    logger.debug("Searching for field of type " 
      + childClass.getSimpleName()); 
    for (Field f : parentClass.getDeclaredFields()) { 

     String type = f.getGenericType().toString(); 
     if (f.getType().isInterface() 
       && f.getGenericType().toString().contains("java.util.Set")) { 
      logger.debug("This field is a collection"); 
      isCollection = true; 
      type = type.substring(type.indexOf("<") + 1); 
      type = type.substring(0, type.length() - 1); 
     } 

     if (isCollection) { 
      logger.debug("Field= " + f.getName() + " " 
        + f.getGenericType()); 
      if (type.equals(childClass.getName())) { 
       logger.debug("*****MATCH FOUND"); 
       fieldName = f.getName(); 
       break; 
      } 
     } else { 
      logger.debug("Type=" + f.getType().getName() + " childType=" 
        + childClass.getName()); 
      if (f.getType().getName().equals(childClass.getName())) { 
       logger.debug("*****MATCH FOUND"); 
       fieldName = f.getName(); 
       break; 
      } 

     } 

    } 

    return fieldName; 
} 


    private void setCollection(Object result, Set collection, String fieldName, 
     Class childClass) { 

    String methodName = "set" + fieldName.substring(0, 1).toUpperCase() 
    + fieldName.substring(1); 
    logger.debug("trivial setter is :" + methodName); 
    Class<?>[] args = new Class<?>[] { java.util.Set.class }; 
    // try the trivial case 
    boolean methodFound = false; 
    Method method = null; 
    try { 
     method = result.getClass().getMethod(methodName, args); 
     methodFound = true; 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } catch (NoSuchMethodException e) { 
     logger.debug("Method not found by trivial method"); 

    } 

    if (!methodFound) { 
     FindMethod: for (Method m : result.getClass().getMethods()) { 
      // logger.debug(m.getName()); 
      for (Type t : m.getGenericParameterTypes()) { 
       // logger.debug("\t"+t); 
       String type = t.toString(); 
       type = type.substring(type.indexOf("<") + 1); 
       type = type.substring(0, type.length() - 1); 
       if (type.equals(childClass.getName())) { 
        logger.debug("***Found the Setter Method"); 
        method = m; 
        break FindMethod; 
       } 
      }// end for parameter Types 

     }// end for Methods 

    }// end if 

    invokeMethod(method, result, false, collection); 

} 



private void invokeMethod(Method method, Object obj, boolean initialize, 
     Object... args) { 

    try { 
     if (method != null) { 
      if (initialize) 
       Hibernate.initialize(method.invoke(obj, args)); 
      else 
       method.invoke(obj, args); 

     } 
     logger.debug("Method executed successfully"); 
    } catch (IllegalArgumentException e) { 

     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
    } 

} 
+2

これは私の問題を解決するとは思わない。私はオブジェクトのリストをロードするとき、私はこのオブジェクトの子をロードしたくありません。ありがとう。 – codea

関連する問題