获取所有属性是否会引起加入?

时间:2016-02-24 21:26:27

标签: java hibernate hql

我的实体如下所示:简化我只是显示两个字段。我们决定一次性获取所有属性。

    @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;

左连接:(这会返回重复的记录。)

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

左连接与distinct:这给出了“ORA-01791:不是SELECTed表达式”,因为我在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

左连接提取:这很好,没有重复。但是在拉动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

获取所有属性:无重复项。表现更好。但.. 当我尝试查询下面这样的人时(这个人没有任何代理):它返回人员记录(这意味着它正在进行左连接)。

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

但是当我在下面做的时候,我不会把这个人记录下来。 (差异是按顺序添加代理的字段,在这种情况下似乎没有做左连接。)

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

我所期待的是避免重复,可以对所有表现良好的人进行排序。

1 个答案:

答案 0 :(得分:1)

导航路径语法(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

修改

distinct案例中的

left join不起作用,因为根据select distinct子句中提到的列中未包含的列进行排序没有意义。

如果您想在查询中急切地加载延迟关联,那么您别无选择,只能执行left join fetch。但也会返回重复项。要消除它们,只需将返回的列表添加到LinkedHashSet以保留返回的订单:

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

关于这种方法的糟糕表现,Hibernate与它没有任何关系。您可能在左连接提取的实体中有一些急切加载的实体(因此遇到了n + 1选择问题),或者复制的实体非常大(从而制作和传输大型结果集)。

您可能希望使用@BatchSize而不是left-join-fetching集合来避免性能问题。