2010-06-25 4 views
10

J'ai une requête SQL personnalisée dans Hibernate (3.5.2) dans laquelle je veux retourner un objet mappé, et un objet associé (joint). Cependant, Hibernate semble me donner une liste de tableaux plutôt qu'une liste d'objets.Hibernate requête SQL personnalisée avec join - évitant de retourner une liste de tableaux

Pour simplifier ma situation un peu: -

Entité1 contient une clé étrangère à Entity2, et les objets mis en correspondance sont mis en place afin que Entité1 a une propriété d'objet faisant référence Entity2. Je souhaite récupérer une liste d'objets Entity1, mais avec la référence d'objet associée déjà initialisée (de sorte que l'objet associé a été chargé).

Maintenant, je peux le faire avec une requête SQL personnalisée comme ceci:

final SQLQuery qry = hibernateSession.createSQLQuery(
    "select {entity1.*}, {entity2.*} from entity1 inner join entity2 on entity1.fk = entity2.id "); 

qry.setReadOnly(true); 
qry.addEntity("entity1", Entity1.class); 
qry.addJoin("entity2", "entity1.entity2"); 

List list = qry.list(); // Returns list of arrays!! 

Cela fonctionne, en ce que tous les objets sont correctement entity1 initialisées. Cependant, la liste que je récupère n'est PAS une liste simple d'objets Entity1. C'est en fait une liste de tableaux, où chaque tableau contient 2 éléments - Entity1 et Entity2. Je suppose que c'est parce que j'ai mis deux entrées d'alias dans la clause SELECT.

Si je supprime le second alias (pour Entity2), je reçois simplement des erreurs "column not found" - probablement parce que Hibernate ne trouve pas les champs pour initialiser entity2.

Des idées? J'ai une requête qui peut retourner les champs pour l'objet primaire et associé, mais je veux que la liste retournée soit simplement une liste d'objets Entity1.

Commentaire préemptif: Oui, je sais que je pourrais probablement restructurer cela et faire la requête d'une manière différente (API de critères, etc.). Mais c'est ce que je suis coincé pour le moment. Dans cette situation particulière, je suis contraint par d'autres facteurs, alors j'espérais qu'il y avait juste une façon de dire à Hibernate ce que je veux!

Merci.

+0

Vous souhaitez specifially faire avec une requête SQL natif, ou serait HQL faire? –

+0

Vous pouvez faire une jointure interne en utilisant HQL sur des relations non mappées comme ceci: 'select * from Entity1 e1, Entity2 e2 où e1.fk = e2.id'. [Cela malheureusement ne fonctionne pas pour les jointures externes] (http://stackoverflow.com/questions/9892008/hql-left-join-of-un-related-entities). – r0estir0bbe

+0

c'est facile dans HQL, ce qui est dans votre requête qui ne peut pas être fait avec HQL? –

Répondre

0

Je n'ai pas mise en veille prolongée devant moi pour tester, en regardant le manuel de mise en veille prolongée semble suggérer ce petit changement:

final SQLQuery qry = hibernateSession.createSQLQuery(
    "select {entity1.*} from Entity1Table entity1 inner join Entity2Table entity2 on entity1.fk = entity2.id "); 

qry.setReadOnly(true); 
qry.addEntity("entity1", Entity1.class); 
qry.addJoin("entity1.entity2"); 

Cela devrait vous redonner seulement les objets entity1, avec la propriété Entity2 déjà initialisé.

Si cela ne fonctionne pas, essayez de remplacer la jointure interne dans le SQL avec une clause where, à savoir

select {entity1.*} from Entity1Table entity1, Entity2Table entity2 WHERE entity1.fk = entity2.id "); 

C'est alors syntaxiquement équivalent à l'exemple donné dans la documentation de mise en veille prolongée.

+0

La modification de la syntaxe de jointure ne fonctionne pas. Et la suppression des colonnes pour entity2 de la clause select aboutit à une erreur "column not found" lancée par Hibernate. – David

+0

Merci d'avoir essayé. Je suis perplexe - autant que je peux voir, il devrait être exactement comme l'exemple SQL natif dans le texte d'hibernation qui renvoie "chat" avec la propriété "chien" également récupérée. – mdma

+0

Atention! certaines bases de données utilisent Cross Join par défaut (exemple postgresql) Une clause CROSS JOIN produit le produit cartésien de lignes dans deux tables ou plus. L'utilisation de "," n'est pas la même chose que INNER JOIN –

0

Voir si this peut vous aider ...

+0

Ugh. Yucky. Mais cela fonctionnerait, oui. – David

0

Une façon pourrait être d'utiliser Theta-Style rejoint:

Permission est une collection mis en correspondance avec la classe d'utilisateurs.

0

Je pense que ce que vous voulez est une jointure d'extraction. C'est une jointure qui ramène des colonnes de la base de données qui sont transformées en objets, mais où ces objets sont seulement ajoutés au cache de session, plutôt que renvoyés dans les résultats.

Il existe différentes manières de le faire via JPA, l'API Hibernate héritée, l'API de critères hérités, etc.

Si vous utilisez un SQL natif, vous devriez être en mesure de le faire en appelant SQLQuery::addFetch, le remplacement de votre appel à addJoin avec:

qry.addFetch("entity2", "entity1", "fk"); 

Ou quelque chose comme ça. Je dois avouer que je ne comprends pas vraiment ce que les paramètres sont censés signifier, et je n'ai pas pu trouver une bonne documentation à ce sujet avec quelques recherches rapides.

+0

'addFetch' est depuis Hibernate 3.6. La question est pour Hibernate 3.5.2. – xmedeko

+0

@xmedeko: Vous avez raison, bonne prise. Je ne peux pas voir un moyen de faire une pure recherche de fetch sur un 'SQLQuery' avec Hibernate 3.5. –

+0

Cela ne fonctionne pas. 'addFetch' est une variante plus personnalisable de' addJoin' (mais fondamentalement la même chose) qu'elle retourne 'FetchReturn' au lieu de' void'. Malheureusement, 'FetchReturn' ne contient pas d'option pour désactiver le retour explicite de la jointure. – r0estir0bbe

1

Ici Entité 1 (enfant) contient la clé étrangère de l'entité 2 (parent), il devrait y avoir une variable de type parent dans le pojo de la classe Entity1 (enfant). Que c'est « E » maintenant la requête sera:

Select ent1.* from Entity1 ent1 inner join ent1.E.id 

ici id est la clé primaire de Entity2