2011-08-02 4 views
1

J'ai une table appelée SecurityContact qui a une relation many-to-one avec une autre table Contacts. Il a deux colonnes de jointure à Contacts, l'une appelée agentContact et l'autre auditContact. Je suis en train d'exécuter la requête HQL suivante:Hibernate ignorant LEFT JOIN

SELECT sc FROM SecurityContact sc LEFT JOIN sc.agentContact ac LEFT JOIN sc.auditContact ac2 WHERE sc.securityId=:securityId2 

Cependant, Hibernate ignore complètement les déclarations LEFT JOIN et procède à générer des requêtes SQL qui utilise des jointures internes. Cela ne correspond pas du tout à mes objectifs. J'ai essayé de placer des annotations de récupération sans aucune chance. Ce problème m'a rendu fou pendant plus de deux jours, donc toute aide serait très appréciée.

Voici le code de ma classe SecurityContact:

/** 
* The persistent class for the SecurityContact database table. 
* 
*/ 
@Entity 
@FXClass(kind=FXClassKind.REMOTE) 
public class SecurityContact implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Transient private String uid; 
    @FXIgnore 
    public String getUid() { 
     if (uid == null) { 
      uid = "" + securityContactId; 
     } 
     return uid; 
    } 

    public void setUid(String uid) { 
     this.uid = uid; 
    } 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="securityContact_id") 
    private Long securityContactId; 

    @Column(name="security_id") 
    private String securityId; 

    @Column(name="create_date") 
    private String createDate; 

    @Column(name="create_user") 
    private String createUser; 

    @Column(name="modify_date") 
    private String modifyDate; 

    @Column(name="modify_user") 
    private String modifyUser; 

    //uni-directional many-to-one association to AgentContact 

    @ManyToOne 
    @JoinColumn(name="agent_id", referencedColumnName="contact_id") 
    private Contact agentContact; 

    //uni-directional many-to-one association to AuditContact 
    @ManyToOne 
    @JoinColumn(name="audit_id", referencedColumnName="contact_id") 
    private Contact auditContact; 

    public SecurityContact() { 
    } 
    @FXKeyColumn 
    public Long getSecurityContactId() { 
     return this.securityContactId; 
    } 

    public void setSecurityContactId(Long securityContactId) { 
     this.securityContactId = securityContactId; 
    } 

    public String getSecurityId() { 
     return this.securityId; 
    } 

    public void setSecurityId(String securityId) { 
     this.securityId = securityId; 
    } 

    public String getCreateDate() { 
     return this.createDate; 
    } 

    public void setCreateDate(String createDate) { 
     this.createDate = createDate; 
    } 

    public String getCreateUser() { 
     return this.createUser; 
    } 

    public void setCreateUser(String createUser) { 
     this.createUser = createUser; 
    } 

    public String getModifyDate() { 
     return this.modifyDate; 
    } 

    public void setModifyDate(String modifyDate) { 
     this.modifyDate = modifyDate; 
    } 

    public String getModifyUser() { 
     return this.modifyUser; 
    } 

    public void setModifyUser(String modifyUser) { 
     this.modifyUser = modifyUser; 
    } 
    @FXManyToOne(parent="parent", property="contactId") 
    public Contact getAgentContact() { 
     return this.agentContact; 
    } 

    public void setAgentContact(Contact agentContact) { 
     this.agentContact = agentContact; 
    } 
    @FXManyToOne(parent="parent", property="contactId") 
    public Contact getAuditContact() { 
     return this.auditContact; 
    } 

    public void setAuditContact(Contact auditContact) { 
     this.auditContact = auditContact; 
    } 

} 

Voici le SQL généré par le HQL ci-dessus:

select securityco0_.agent_id as col_0_0_, securityco0_.audit_id as col_1_0_, securityco0_.create_date as col_2_0_, securityco0_.create_user as col_3_0_, securityco0_.modify_date as col_4_0_, securityco0_.modify_user as col_5_0_, securityco0_.securityContact_id as col_6_0_, securityco0_.security_id as col_7_0_, agentconta3_.contact_id as contact1_0_0_, agentconta4_.contact_id as contact1_0_1_, agentconta3_.bank_id as bank10_0_0_, agentconta3_.create_date as create2_0_0_, agentconta3_.create_user as create3_0_0_, agentconta3_.email as email0_0_, agentconta3_.fax as fax0_0_, agentconta3_.modify_date as modify6_0_0_, agentconta3_.modify_user as modify7_0_0_, agentconta3_.name as name0_0_, agentconta3_.phone as phone0_0_, agentconta4_.bank_id as bank10_0_1_, agentconta4_.create_date as create2_0_1_, agentconta4_.create_user as create3_0_1_, agentconta4_.email as email0_1_, agentconta4_.fax as fax0_1_, agentconta4_.modify_date as modify6_0_1_, agentconta4_.modify_user as modify7_0_1_, agentconta4_.name as name0_1_, agentconta4_.phone as phone0_1_ from SecurityContact securityco0_ left outer join AgentContact agentconta1_ on securityco0_.agent_id=agentconta1_.contact_id left outer join AgentContact agentconta2_ on securityco0_.audit_id=agentconta2_.contact_id inner join AgentContact agentconta3_ on securityco0_.agent_id=agentconta3_.contact_id inner join AgentContact agentconta4_ on securityco0_.audit_id=agentconta4_.contact_id where securityco0_.security_id=? 
+0

Pourquoi est-ce important si Hibernate utilise une jointure gauche ici? À quelle question essayez-vous de répondre avec la requête HQL? Quels résultats attendez-vous différents d'un simple 'de SecurityContact où securityId =?'? –

+0

@matt Cela est important parce que je veux que Hibernate renvoie les entrées même s'il n'y a pas d'agentContact ou d'auditContact correspondant disponible. Cela ne le fera pas avec une jointure interne. –

+0

mais les associations '@ ManyToOne' ne sont-elles pas optionnelles/nullables par défaut? À quoi ressemble le côté inverse de cette relation dans l'autre classe? Êtes-vous en train de dire qu'un simple 'session.get (SecurityContact.class, securityId)' ne retournera pas une instance où l'un ou l'autre des champs est null? –

Répondre

1

Je l'ai fait quelques essais en ce qui concerne votre problème, et il me semble que vous devez avoir soit un problème dans votre application ou d'un bogue dans la version (obsolète) de mise en veille prolongée, vous êtes en utilisant.

Pour une association @ManyToOne en option, Hibernate devrait déjà être en utilisant une jointure gauche pour interroger l'entité et l'Association (comme il est le seul moyen d'interroger pour l'entité racine si l'entité associée ou non est nulle).

J'ai jeté ensemble un projet d'exemple qui illustre cela à https://github.com/mattnworb/hibernate-sample.

Dans mon exemple de projet, la classe Employee a a unidirectional many-to-one mapping to the Team class:

/** 
* Unidirectional relationship between Employee and Team. 
*/ 
@ManyToOne 
@JoinColumn(name = "team_id") 
private Team team; 

Dans les tests unitaires, il est à la fois un test que la référence Employee.teamis not-null when it is set in the DB, et un autre test qui affirme que Employee.teamis null when not set dans le tableau DB .

En outre, il existe une relation bidirectionnelle similaire entre les entités Company et Employee, avec des tests similaires.

Enfin, dans les journaux, je peux voir que lorsque les requêtes Hibernate pour l'entité Employé (avec un simple session.get(Employee.class, id)), il utilise une jointure gauche pour tirer dans la table teams (j'ai ajouté la ligne me casse):

DEBUG org.hibernate.SQL - sélectionnez employee0_.id comme id1_2_, employee0_.company_id comme company6_1_2_, employee0_.dateOfBirth comme dateOfBi2_1_2_, employee0_.employmentStartDate comme employme3_1_2_, employee0_.firstName comme firstName1_2_, employee0_.lastName comme lastName1_2_, employee0_.team_id comme team7_1_2_, company1_.id comme id0_0_, company1_.name comme name0_0_, team2_.id comme id2_1_, team2_.name comme name2_1_
depuis emp loyees employee0_
left outer rejoindre les entreprises company1_ sur employee0_.company_id = company1_.id
gauche rejoindre les équipes externes team2_ sur employee0_.team_id = team2_.id où employee0_.id =?

Donc, en somme, pour Hibernate d'utiliser une jointure gauche entre vos entités associées, tant que la relation est définie comme option, il devrait y avoir pas besoin d'une HQL spéciale questions à tout - simple session.get() car l'entité racine doit interroger la table de l'entité associée avec une jointure à gauche. Si vous voyez des résultats différents, ceci suggère qu'il y a un bogue dans votre version d'Hibernate (j'utilise 3.6.6.Final ici), ou qu'il y a quelque chose d'incorrect dans votre mapping.

1

Votre HQL join syntax semble bancale. Essayez ceci:

SELECT sc 
FROM SecurityContact sc 
LEFT JOIN FETCH sc.agentContact 
LEFT JOIN FETCH sc.auditContact 
WHERE sc.securityId=:securityId2 
+0

Pour une raison quelconque, Hibernate génère des erreurs lors de la construction de annotated.xml avec votre requête. –

+0

Quel genre d'erreurs? Quelle version d'Hibernate? –

+0

Il me dit essentiellement que le fichier annotated.xml n'a pas pu être généré. J'ai trouvé ceci se produit quand il y a quelque chose que Hibernate n'aime pas à propos de la requête. J'utilise la version 3.4.0. –