我们希望在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也不应与条件"的即兴一起使用。
使用附加where条件t1.partion_key = t2.partition_key
不起作用,因为它将查询的语义从外连接更改为内连接:当没有数据匹配条件时不会保持并忽略该行。
使用oracle语法t1.partion_key = t2.partition_key (+)
也不起作用,因为它会导致混合ANSI和Oracle语法的SQL查询。
我们虽然关于使用组合密钥,但它并不是真正正确的,因为在逻辑级别,密钥只是id
。我们不想让物理数据建模(分区)影响逻辑模型。
我们如何用HQL表达所需的查询?
答案 0 :(得分:3)
1)自从Hibernate 5.1我们可以使用' join' 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
实体中向children
属性添加两个Parent
并将parent
' many - 替换为-one与parentId
实体中的简单Child
属性的关系:
@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。
答案 1 :(得分:1)
在没有复合主键的情况下很难将表分区与Hibernate一起使用,所以你真的没有多少选择。
我想到的一件事是尝试使用额外的where子句和null检查来实现外连接语义:
where t1.partion_key = t2.partition_key OR t2.partition_key is null