获取所有属性是否会在幕后进行左连接?

Does fetch all properties do left join under the hood?

我的实体如下所示:为简化起见,我只显示了两个字段。我们决定执行 fetch all 以一次加载所有属性。

    @Entity     
    public class Person{
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<PhoneNumber> phoneNumbers = new HashSet<>(0);
     @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "AGENCY_ID")
        private Agency agency;

左连接:(此returns重复记录。)

select person
from Person person left join person.agency ag left join person.phoneNumbers 
where upper(person.name) LIKE '%SU%' and upper(person.status.rcode)   = 'ACTIVE'
order by person.agency.name asc, person.id asc

left join with distinct : 这给出了 "ORA-01791: not a SELECTed expression" 因为我在 order 子句中使用了 agency 字段。

select distinct person
    from Person person left join person.agency ag left join person.phoneNumbers 
    where upper(person.name) LIKE '%SU%' and upper(person.Status.rcode)   = 'ACTIVE'
    order by person.agency.name asc, person.id asc

left join fetch:这很好用,没有重复。但对拉动 2000 人的记录有很大的影响。大约需要 15 秒,而左连接需要 1 秒。

select  person
        from Person person left join fetch person.agency ag left join fetch person.phoneNumbers 
        where upper(person.name) LIKE '%SU%' and upper(person.Status.rcode)   = 'ACTIVE'
        order by person.agency.name asc, person.id asc

获取所有属性:没有重复项。执行 better.But.. 当我尝试查询如下人员时(此人没有任何代理):它 returns 人员记录(这意味着它正在进行左连接)。

 select person
    from Person person 
    fetch all properties
    where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
    order by  person.id asc

但是当我执行以下操作时,我没有取回人员记录。 (不同的是在order by clause中添加了agency的字段,这里好像没有做left join)

select person
from Person person 
fetch all properties
where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
order by person.agency.name asc, person.id asc

我要找的是避免重复,按所有领域表现好的人排序。

导航路径语法 (person.agency) 总是被翻译成内部连接,这就是为什么没有代理的人不包含在结果集中。

您必须显式编写外连接以避免隐式内连接:

select person
from Person person left outer join person.agency a
where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
order by a.name asc, person.id asc

编辑

distinctleft join 情况下不起作用,因为按 select distinct 子句中提到的列中未包含的列排序没有意义。

如果你想在查询中急切加载惰性关联,那么你别无选择,只能这样做left join fetch。但是也会返回重复项。要消除它们,只需将返回的列表添加到 LinkedHashSet 以保留返回的顺序:

List<Persons> result = new ArrayList(new LinkedHashSet(list))

关于这种方法的性能不好,Hibernate与它无关。您可能在左连接获取的实体中有一些急切加载的实体(因此遭受 n+1 选择问题),或者重复的实体非常大(因此制作和传输一个大的结果集)。

您可能希望使用 而不是左连接提取集合以避免性能问题。