了解在Join表上为一对多和多对一生成的查询

时间:2014-09-10 02:20:01

标签: java sql hibernate

我正在关注hibernate documentation与关联表的一对多和多对一的单向关联。

我试图通过创建Person& amp;来实现一个简单的例子。像这样的地址实体:

Person has an id and name property with setters & getters
Address has an id and name property with setters & getters

我在文档中给出了相同的映射文件,用于一对多和多对一。然后我创建了一个小程序来获取Person个实体以及相应的Address个实体:

one-to-many

    for (Person person : list) {
        System.out.println(person.getId());
        for (Address address : person.getAddresses()) {
            System.out.println(address);    
        }
    }

对于下面生成的hibernate查询:

Hibernate: select person0_.personId as personId1_1_ 
from Person person0_

Hibernate: select addresses0_.personId as personId1_1_0_, addresses0_.addressId as addressId2_2_0_, address1_.addressId as addressId1_0_1_ 
from PersonAddress addresses0_ 
inner join Address address1_ 
on addresses0_.addressId=address1_.addressId 
where addresses0_.personId=?

many-to-one

   List<Person> list = session.createQuery("from Person").list();
            for (Person person : list) {
                System.out.println(person.getId());
                System.out.println(person.getAddress());
            }
Hibernate: select person0_.personId as personId1_1_, person0_.name as name2_1_, person0_1_.addressId as addressId2_2_ 
from Person person0_ 
left outer join PersonAddress person0_1_ 
on person0_.personId=person0_1_.personId

Hibernate: select address0_.addressId as addressId1_0_0_, address0_.name as name2_0_0_ 
from Address address0_ 
where address0_.addressId=?

从生成的查询中,对于one-to-many,最初的查询是从Person表获取记录,以获取所有人员,然后获取PersonAddress和{{1}之间的JOIN地址}}。

Address最初它在many-to-onePersonAddress之间有LEFT OUTER JOIN以获取Address记录,然后它到达Person表以获取来自Address表的记录。

所以我怀疑为什么Address案例没有遵循many-to-one的相同方法,只打了one-to-many表,因为最初我试图只获取我的HQL中的Person实体。请帮助我理解这一点。

1 个答案:

答案 0 :(得分:3)

对于OneToMany案例,一个人拥有一组地址。该集合可以有0个,一个或多个地址。这个系列懒洋洋地填充。因此,当从数据库加载人员时,执行第一个查询以获取人员的字段(名称等)。 Hibernate还不知道这个人是否有地址,并不关心。它将地址集合设置为惰性集合。第一次在这个惰性集合上调用一个方法时,会执行第二个查询来加载该人的所有地址并填充该集合。

对于ManyToOne案例,某人的字段地址为Address。当你加载一个人时,Hibernate应该将该字段初始化为什么。如果它将它设置为null并且您要求该地址,它将返回null,即使该人有一个地址,这是错误的。如果它将它设置为一个惰性地址代理并且你要求该地址,它将返回非空代理,即使该人没有地址,这也是错误的。所以Hibernate必须知道这个人是否有地址。如果没有,则将该字段设置为null。如果有,则将地址设置为地址代理。这就是为什么要执行额外的左外连接的原因:知道该人是否有地址(以及该地址的ID是什么),如果有的话。