Hibernate:LEFT JOIN FETCH 多列用于连接

ewe*_*nli 7 database hibernate jpa hql

我们想在 HQL 中使用两列进行左外连接两个表的连接。

连接的第二列在逻辑级别没有相关性,并且不会以任何方式限制结果集。它是分区键,仅用作加速物理数据访问的优化。

在 SQL 中,它类似于

select * 
from t1 
left outer join t2 
on t1.id = t2.parent_id 
and t1.partion_key = t2.partition_key
Run Code Online (Sandbox Code Playgroud)

我们尝试的以下方法不起作用:

  • 我们可以在 HQL 中进行外连接,left join fetch并且可以在连接中指定附加条件, with但两者不能结合在一起。文档中明确提到了此限制:“Fetch 也不应与即席条件一起使用”。

  • 使用额外的 where 条件t1.partion_key = t2.partition_key不起作用,因为它将查询的语义从外连接更改为内连接:当没有数据匹配时,条件不成立并且行被忽略。

  • 使用 oracle 语法t1.partion_key = t2.partition_key (+)也不起作用,因为它会导致 SQL 查询混合了 ANSI 和 Oracle 语法。

  • 我们虽然考虑使用组合键,但它并不是真正正确的,因为在逻辑级别,键只是id. 我们不想让物理数据建模(分区)影响逻辑模型。

我们如何用 HQL 表达所需的查询?

Cep*_*pr0 5

1) 从 Hibernate 5.1 开始,我们可以在 HQL 查询中对不相关的类使用“join”。在这种情况下,我们可以使用这个 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
Run Code Online (Sandbox Code Playgroud)

2)另一种方法是修改实体如下(在实体中的属性中添加两个JoinColumns并将“多对一”关系替换为实体中的简单属性):childrenParentparentparentIdChild

@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;
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用以下简单的 JPQL 查询:

select distinct p as parent from Parent p left join fetch p.children c
Run Code Online (Sandbox Code Playgroud)

这两个查询都被 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) 
Run Code Online (Sandbox Code Playgroud)

工作演示在这里


Dra*_*vic 1

如果没有复合主键,很难在 Hibernate 中使用表分区,因此您实际上没有太多选择。

我想到的一件事是尝试仍然通过附加的 where 子句和 null 检查来实现外连接语义:

where t1.partion_key = t2.partition_key OR t2.partition_key is null
Run Code Online (Sandbox Code Playgroud)