Hibernate忽略LEFT JOIN

时间:2011-08-02 15:37:53

标签: java hibernate

我有一个名为SecurityContact的表,它与另一个表Contacts有多对一的关系。它有两个连接列到Contacts,其中一个名为agentContact,另一个名为auditContact。我正在尝试运行以下HQL查询:

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

但是,Hibernate完全忽略了LEFT JOIN语句并继续生成利用内部联接的SQL。这根本不适合我的目的。我试过设置获取注释没有运气。这个问题让我疯狂了两天多,所以任何帮助都会非常感激。

以下是我的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;
    }

} 

以下是来自上述HQL的生成的SQL:

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=?

2 个答案:

答案 0 :(得分:1)

你的HQL join syntax看起来很不稳定。试试这个:

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

答案 1 :(得分:1)

我已经针对您的问题做了一些测试,在我看来,您的映射中存在问题,或者您正在使用的Hibernate的(过时)版本中存在错误。

对于可选的@ManyToOne关联,Hibernate 应该已经使用左连接来查询实体及其关联(因为它是查询根实体的唯一方法,无论是不是关联的实体是空的。)

我汇总了一个示例项目,该项目在https://github.com/mattnworb/hibernate-sample上说明了这一点。

在我的示例项目中,Employee班级有a unidirectional many-to-one mapping to the Team class

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

在单元测试中,有一个测试Employee.team引用is not-null when it is set in the DB,另一个测试在数据库表中断言Employee.team is null when not set

此外,CompanyEmployee实体之间存在类似的双向关系,并进行了类似的测试。

最后,在日志中我可以看到当Hibernate查询Employee实体时(使用简单的session.get(Employee.class, id)),它使用左连接来拉入teams表(我添加了换行符)自己):

  

DEBUG org.hibernate.SQL - 选择employee0_.id为id1_2_,employee0_.company_id为company6_1_2_,employee0_.dateOfBirth为dateOfBi2_1_2_,employee0_.employmentStartDate为employme3_1_2_,employee0_.firstName为firstName1_2_,employee0_.lastName为lastName1_2_,employee0_.team_id作为team7_1_2_,company1_.id为id0_0_,company1_.name为name0_0_,team2_.id为id2_1_,team2_.name为name2_1_
  来自员工employee0_
  left outer join company company__ on employee0_.company_id = company1_.id
  left outer join team team2_ on employee0_.team_id = team2_.id where employee0_.id =?

总而言之,为了让Hibernate在关联实体之间使用左连接,只要将关系设置为可选,就根本不需要特殊的HQL查询 - 简单{{1}对于根实体,应该使用左连接查询关联实体的表。如果您看到不同的结果,这表明您的Hibernate版本中存在错误(我在这里使用3.6.6.Final),或者您的映射中存在不正确的内容。