我们想在 HQL 中使用两列进行左外连接两个表。
连接的第二列在逻辑级别没有相关性,并且不以任何方式限制结果集。它是分区键,仅用作加速物理数据访问的优化。
在 SQL 中它会是这样的
select *
from t1
left outer join t2
on t1.id = t2.parent_id
and t1.partion_key = t2.partition_key
我们尝试的以下方法均无效:
我们可以在 HQL
left join fetch
中进行外部连接,并且可以使用with
在连接中指定附加条件,但两者都不能结合在一起。 documentation 中明确提到了此限制: “Fetch 也不应与 impromptu with condition 一起使用”。使用额外的 where 条件
t1.partion_key = t2.partition_key
不起作用,因为它将查询的语义从外连接更改为内连接:当没有数据匹配时条件不成立,该行被忽略。使用 oracle 语法
t1.partion_key = t2.partition_key (+)
也不起作用,因为它会导致 SQL 查询混合了 ANSI 和 Oracle 语法。我们考虑过使用组合键,但这并不正确,因为在逻辑层面上,键只是
id
。我们不想让物理数据建模(分区)影响逻辑模型。
我们如何用 HQL 表达我们想要的查询?
最佳答案
1) 自 hibernate 以来 5.1我们可以在 HQL 查询中对不相关的类使用“加入”。在这种情况下,我们可以使用这个 HQL 查询:
select
p as parent,
c as child
from
Parent p
left join Child c on c.parentId = p.id and c.partitionKey = p.partitionKey
2) 另一种方法是如下修改实体(将两个 JoinColumn
添加到 Parent
实体中的 children
属性并替换 parent
与 Child
实体中的简单 parentId
属性的“多对一”关系):
@Entity
public class Parent {
@Id
@GeneratedValue
private Integer id;
@Column(name = "partition_key")
private Integer partitionKey;
@OneToMany
@JoinColumns({
@JoinColumn(name = "parent_id", referencedColumnName = "id"),
@JoinColumn(name = "partition_key", referencedColumnName = "partition_key")
})
private List<Child> children;
}
@Entity
public class Child {
@Id
@GeneratedValue
private Integer id;
@Column(name = "partition_key")
private Integer partitionKey;
@Column(name = "parent_id")
private Integer parentId;
// @ManyToOne
// private Parent parent;
}
然后我们可以使用以下简单的 JPQL 查询:
select distinct p as parent from Parent p left join fetch p.children c
这两个查询都由 Hibernate 翻译为喜欢这个 SQL 查询:
select
p.id,
p.partition_key,
s.id,
s.parent_id,
s.partition_key
from
parents p
left outer join children c on (c.parent_id=p.id and c.partition_key=p.partition_key)
工作演示是 here .
关于database - Hibernate:LEFT JOIN FETCH 具有用于连接的多列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49118193/