Hibernate:LEFT JOIN FETCH,包含多列连接

时间:2018-03-05 19:38:48

标签: 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

我们尝试过的以下方法并不奏效:

  • 我们可以在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表达所需的查询?

2 个答案:

答案 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