Hibernate HQL join fetch ne récupérant pas récursivement
J'ai la requête suivante et la méthode
private static final String FIND = "SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";
@Override
public Domain find(Long domainId) {
Query query = getCurrentSession().createQuery(FIND);
query.setLong("domainId", domainId);
return (Domain) query.uniqueResult();
}
Avec Domain
comme
@Entity
@Table
public class Domain {
@Id
@GenericGenerator(name = "generator", strategy = "increment")
@GeneratedValue(generator = "generator")
@Column(name = "domain_id")
private Long domainId;
@Column(nullable = false, unique = true)
@NotNull
private String name;
@Column(nullable = false)
@NotNull
@Enumerated(EnumType.STRING)
private DomainType type;
@OneToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.EAGER)
@JoinTable(joinColumns = {
@JoinColumn(name = "domain_id")
}, inverseJoinColumns = {
@JoinColumn(name = "code")
})
@NotEmpty
@Valid //needed to recur because we specify network codes when creating the domain
private Set<NetworkCode> networkCodes = new HashSet<>();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(joinColumns = {
@JoinColumn(name = "parent", referencedColumnName = "domain_id")
}, inverseJoinColumns = {
@JoinColumn(name = "child", referencedColumnName = "domain_id")
})
private Set<Domain> operators = new HashSet<>();
//more
}
Je m'attends à ce que cette seule requête pour récupérer le Set<NetworkCode>
et Set<Domain
> les relations, mais il ne le fait pas. Dire que le Domain
j'ai une requête a deux opérateurs, Hibernate effectuer 1 + 2 * 2 = 5 requêtes
Hibernate: select distinct domain0_.domain_id as domain1_1_0_, domain2_.domain_id as domain1_1_1_, networkcod4_.code as code2_2_, domain0_.name as name1_0_, domain0_.type as type1_0_, domain2_.name as name1_1_, domain2_.type as type1_1_, operators1_.parent as parent1_0__, operators1_.child as child4_0__, networkcod3_.domain_id as domain1_1_1__, networkcod3_.code as code5_1__ from domain domain0_ left outer join domain_operators operators1_ on domain0_.domain_id=operators1_.parent left outer join domain domain2_ on operators1_.child=domain2_.domain_id inner join domain_network_codes networkcod3_ on domain0_.domain_id=networkcod3_.domain_id inner join network_code networkcod4_ on networkcod3_.code=networkcod4_.code where domain0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Je suppose que c'est parce que je suis de rejoindre les opérateurs Domain
éléments, mais ils ont à se joindre à eux-mêmes. Est-il une requête HQL je peut exécuter qui permettrait de faire les deux?
source d'informationauteur Sotirios Delimanolis
Vous devez vous connecter pour publier un commentaire.
Si vous savez que vous avez seulement deux niveaux dans votre arbre, avez-vous pensé à rejoindre un niveau plus profond. Quelque chose comme ci-dessous?
Hibernate Relations Travaille avec différents Chercher des Stratégies..!!
Hibernate fournit 4 stratégies pour la récupération de données:
SÉLECTIONNEZ
REJOINDRE
- CI
LOT
Hibernate également fait la distinction entre (quand est ce que les associations sont récupérées)
1.Chargement immédiat -
2.Paresseux de la collection de l'extraction de -
3."Extra-paresseux de la collection" extraction -
4.Proxy de l'extraction de -
5."No-proxy" chercher -
6.Paresseux attribut fetch -
Vous avez marqué vos associations DÉSIREUSES. Donc, quoi que vous fassiez dans votre requête, Hibernate va charger tous les domaines et de codes de réseau des chargés de domaines. Et il va charger les domaines et les codes de réseau de domaines supplémentaires, etc. etc. jusqu'à ce que toute la collection des charges de retour à vide des collections ou les entités qui ont déjà été chargé.
Pour éviter cela, faites vos collections paresseux (comme ils le sont par défaut). Ensuite, le chargement d'un domaine avec ses opérateurs et ses codes de réseau se charge juste que.
Vos DÉSIREUX de cartographie ne seront considérés automatiquement en veille prolongée si vous utilisez l'API des Critères de la requête.
Si vous utilisez les requêtes HQL, vous devrez ajouter manuellement l'EXTRACTION de mots clés pour votre Joint à la force Hibernate pour inclure les relations dans la première requête et d'éviter les requêtes suivantes.
C'est Hibernate spécifiques et peuvent fonctionner différemment sur d'autres Orm.
Voir cette question/réponse pour un angle légèrement différent.
Il n'est pas documenté, mais en avez-vous essayez de définir le
FetchMode
?Vous pouvez le faire soit en utilisant les Critères de l'API:
domainCriteria.setFetchMode("operators", JOIN)
ou de l'utilisation@Fetch(JOIN)
à la relation de définition.L'annotation (et seulement l'annotation comme il semble) permet également de définir un mode de lecture de
SUBSELECT
qui devrait au moins nous retenir d'Hibernation pour exécuter des 3 requêtes max. Ne sachant pas votre jeu de données, je suppose que ce doit être le chemin à parcourir pour vous, comme une grosse grosse jointure sur les tables ne semble pas trop sain. Le mieux pour comprendre, pour vous-même, je suppose...Puisque vous avez déjà spécifié
FetchType.EAGER
pour les deuxnetworkCodes
etoperators
chaque fois que vous allez requêtedomain
hibernate va charger les deuxnetworkCodes
etoperators
. C'est toute l'idée de laEAGER
de l'extraction de modeDe sorte que vous pouvez changer votre requête simple à suivre:
API détails ici
Cheers !!
Ma première observation est que vous n'avez pas besoin d'écrire une requête HQL contenant les jointures si votre mappages de dire qu'ils doivent être chargé avec impatience.
Cependant, vous pouvez dire à l'Hibernation pour l'utilisation de l'extraction de la stratégie en tant que sous-sélectionnez cette option si vous ne souhaitez pas utiliser les jointures.
Hibernate génère la requête SQL pour charger les objets lors du démarrage basé sur la mappages et les caches. Cependant, dans votre cas, vous en avez un à de nombreux imbriquée relation avec soi et profondeur arbitraireregarde donc comme il ne sera pas possible pour hibernate pour décider de la main avant de l'
le sql correctement désireux d'extraction. Donc, il serait nécessaire d'envoyer plusieurs jointures des requêtes en fonction de la profondeur du Domaine parent vous vous interrogez au moment de l'exécution.
Pour moi, on dirait que vous pensez que le HQL et le SQL/('s) dans votre dossier, vous pouvez en avoir un pour un correpondence qui n'est pas
vrai. Avec HQL vous interrogez des objets et de l'orm décide de la façon de charger l'objet et de ses relations (eager/paresseux) basé sur le
mappages ou vous pouvez spécifier lors de l'exécution trop ( pour l'e.g, un paresseux de l'association dans la cartographie peut être remplacée par de la Requête api, mais pas vice-versa).
Vous pouvez dire à l'orm quoi de charge ( ma désireux de marquage ou paresseux ) et comment charger avec impatience ( soit à l'aide de rejoindre /sub select).
Mise à JOUR
Lorsque j'exécute la requête suivante sur votre modèle de domaine
Je peux voir que la networkCode et l'opérateur collections sont de l'instance PersistentSet ( c'est Hibernate wrapper) et les deux ont initialisé propriété est définie sur true. Également dans le contexte de session, je peux voir les domaines avec le domaine et les opérateurs énumérés.
Donc, qu'est-ce que vous faire penser qu'ils ne sont pas chargé avec impatience ?
C'est comment mon domaine ressemble