我有一个名为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=?
答案 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。
此外,Company
和Employee
实体之间存在类似的双向关系,并进行了类似的测试。
最后,在日志中我可以看到当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),或者您的映射中存在不正确的内容。