Hibernate désireux de chargement (récupération de toutes les propriétés ne fonctionne pas)
Fondamentalement, je veux désireux de charge de propriétés. J'ai la requête HQL suivante:
SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties
Je m'attends à ce à exécuter une requête uniquement. Au lieu de cela je suis N+1 requêtes.
Le code est le suivant:
Query q = mySession.createQuery(
"SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties")
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
System.out.println(line);
}
La sortie-je obtenir (avec hibernate.show_sql
ensemble de true
) est:
Hibernate: select user0_.id as col_0_0_, user0_.name as col_1_0_, user0_.id as col_2_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=1, obj=User@b6548 [id='1' name='John' ], text=John}
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=2, obj=User@4865ce [id='2' name='Arnold' ], text=Arnold}
Ps: La situation est exactement la même chose sans transformateurs.
Edit:
Le fichier avec l'entité-mappings:
<hibernate-mapping>
<class name="User" table="user">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="location"/>
<map name="customPrices" table="custprice">
<key column="user"/>
<map-key-many-to-many column="product" class="Product"/>
<element column="price" type="double"/>
</map>
</class>
<class name="Product" table="product">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="listprice"/>
</class>
</hibernate-mapping>
J'ai essayé d'ajouter lazy="false"
pour la classe et pour les propriétés individuelles. Pas de différence.
Mon fichier de configuration:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://192.168.0.203/hibtest</property>
<property name="connection.username">hibtest</property>
<property name="connection.password">hibb345</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="combined.hbm.xml" />
</session-factory>
</hibernate-configuration>
Edit2:
Même le code suivant provoque N+1 de la requête. Bien que je ne récupérer l'ID de champ, qui, selon la documentation ne doit pas provoquer des objets à charger.
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
User u = (User)((Map)line).get("obj");
System.out.println(u.getId());
}
- s'il vous plaît ajouter votre hibernate mapping. Il semble que vous l'emplacement de l'association est paresseusement chargé.
- Exactement ce que vous essayez d'atteindre avec cette requête? Pourquoi avez-vous besoin de spécifier
id
etname
séparément? - Harel j'ai ajouté les fichiers de configuration à la question.
- Les résultats sont exactement ce que j'attends. Le seul moyen d'Hibernate récupère le résultat est irréaliste. Même quand j'ai ajouter explicitement
fetch all properties
. - Est-il une raison particulière pour vous: 1. utilisation iterate() au lieu de (liste)? 2. sélectionner individuellement les propriétés situées le long de la principale entité?
- Les résultats sont nourris à un autre API. Mais oui: à l'aide de
.list().interator()
au lieu de.interate()
causes désireux de chargement. Vous pourriez poster cela comme une réponse trop. - Pas très intuitif comportement bien. Je me demande combien de mines terrestres comme ce mensonge en veille prolongée... - Harel s'il vous Plaît écrire une réponse courte, donc je ne peux l'accepter 🙂
Vous devez vous connecter pour publier un commentaire.
Le problème était avec
.iterate()
. Selon L'API Hibernate docs:C'est une fonction spéciale pour être utilisé quand on attend les objets qui en résultent pour être déjà mis en cache. Ils seront (paresseux) chargé lors de l'accès.
Donc, pour utilisation générale, pour obtenir un itérateur sur un résultat d'une requête, vous devez utiliser
.list().iterate()
.Merci pour Eran Harel pour l'aider.
Dans essense, la cause de votre problème est une tentative d'intégrer le résultat de la logique de transformation dans une requête.
Je pense qu'il serait mieux de faire une simple requête HQL et appliquez ensuite votre résultat spécifique de la logique de transformation personnalisé dans un
ResultTransformer
, quelque chose comme ceci:.iterate()
- apparemment il oblige certains superlazy mode sur tous les autres paramètres..list().interator()
à la place. - À part le fait que le nom de la fonction doit suggérer cette spéciale comportement en premier lieu.Ressemble, il ne peut pas récupérer l'obj dans une seule requête avec des colonnes distinctes.
Puisque vous utilisez les mêmes valeurs de l'Utilisateur pour les autres colonnes, l'exemple de @axtavt semble la meilleure solution.
.list().interator()
doit être utilisé.