如何在使用@OneToOne和@OneToMany时创建Hibernate OUTER JOIN [英] How can I make Hibernate OUTER JOIN when using @OneToOne and @OneToMany

查看:88
本文介绍了如何在使用@OneToOne和@OneToMany时创建Hibernate OUTER JOIN的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个名为 employee 的表,其中 employee_id name supervisor_id
employee_supervisor 字段为 supervisor_id 名称。对于 supervisor_id 雇员 employee_supervisor 表存在外键关系。 code>列。



如果我在 Employee 类中做了多对一的注解映射,我该如何确保Hibernate使用LEFT OUTER JOIN加入相关实体?

解决方案

在我的测试中,Hibernate默认做了LEFT OUTER JOIN。但是,您可以确保它始终使用带注释的LEFT OUTER JOIN。我花了一些时间嘲笑你的情况,使用从我的模板作为基地的双向一对多映射,然后更改类名以符合您的情况。



我想出的类如下所示:

EmployeeSupervisor类:

  @Entity(name =EMPLOYEE_SUPERVISOR)
公共类EmployeeSupervisor {
@Id
@GenericGenerator(name =gen,strategy =increment)
@GeneratedValue(generator =gen)
@Column(name =id)
private int supervisorId ;

@Column
私人字符串名称;

@OneToMany(mappedBy =supervisor)
私人清单<员工>雇员;
....
}

员工类别:

  @Entity 
public class Employee {
@Id
@GenericGenerator(name =gen,strategy = 增量)
@GeneratedValue(generator =gen)
@Column(name =id)
private int employeeId;

@Column
私人字符串名称;

@ManyToOne
@Fetch(FetchMode.JOIN)
@JoinColumn(name =supervisorId)
私人EmployeeSupervisor监督员;
....
}

注释确保您始终使用 LEFT OUTER JOIN @Fetch(FetchMode.JOIN >注释,它告诉Hibernate加载关联的记录使用 LEFT OUTER JOIN 的相同select语句(参见其他类型 FetchMode 的文档,以及每个类型的内容)。然后,我在jUnit中模拟了数据库,配置Hibernate在log4j中打印所有生成的SQL

  log4j.logger.org.hibernate.SQL = DEBUG 
log4j.logger.org.hibernate.type = TRACE

并且运行了一个非常基本的单元测试。

  public class EmployeeDAOTest扩展SpringTest {

@Autowired
private Employe eDAO dao;

私人员工testLinkedEmployee;
私人员工testUnlinkedEmployee;
私人EmployeeSupervisor testSupervisor;

@BeforeClass
public static void setUpBeforeClass()抛出异常{
System.out.println(Starting DAO Test);


@AfterClass
public static void tearDownAfterClass()抛出异常{
System.out.println(Finished DAO Test);
}

@Before
public void setUp()抛出Exception {
//不相关的可怕设置代码被剪掉。
/ *在数据库中设置2名员工和一名EmployeeSupervisor。
*将一名员工链接到EmployeeSupervisor,而不是其他
* /
}

@Test
@Transactional
public void test ){
Employee actualLinkedEmployee = dao.getEmployee(testLinkedEmployee.getEmployeeId());
Employee actualUnlinkedEmployee = dao.getEmployee(testUnlinkedEmployee.getEmployeeId());

assertNotNull(链接的员工的主管没有被选中,actualLinkedEmployee.getSupervisor());
assertNull(未关联的员工的主管不为空,actualUnlinkedEmployee.getSupervisor());


我的DAO非常简单:

  @Repository 
public class EmployeeDAOImpl implements EmployeeDAO {
$ b $ @Autowired
private SessionFactory sessionFactory;

@Override
public Employee getEmployee(int id){
Criteria query = sessionFactory.getCurrentSession()。createCriteria(Employee.class);
query.add(Restrictions.idEq(id));
return(Employee)query.uniqueResult();
}
}

和SQL输出如下:

  [junit] / *条件查询* / select 
[junit] this_.id as id1_1_1_ ,
[junit] this_.name as name2_1_1_,
[junit] this_.supervisorId as supervis3_1_1_,
[junit] employeesu2_.id as id1_0_0_,
[junit] employeesu2_.name as name2_0_0_
[junit] from
[junit] Employee this_
[junit] left outer join
[junit] EMPLOYEE_SUPERVISOR employeesu2_
[junit] this_.supervisorId = employeesu2_.id
[junit]其中
[junit] this_.id =? 01:23:54:0.668
[junit] binding parameter [1] as [INTEGER] - 5 01:23:54:0.671

[junit] / *条件查询* / select
[junit] this_.id as id1_1_1_,
[junit] this_.name as name2_1_1_,
[junit] this_.supervisorId as supervis3_1_1_,
[junit] employeesu2_.id as id1_0_0_,
[junit] employeesu2_.name as name2_0_0_
[junit] from
[junit] Employee this_
[junit] left outer join
[junit] EMPLOYEE_SUPERVISOR employeesu2_
[junit] on this_.supervisorId = employeesu2_.id
[junit]其中
[junit] this_.id =? 01:23:54:0.704
[junit] binding parameter [1] as [INTEGER] - 6 01:23:54:0.704

应该注意的是,默认情况下,Hibernate似乎急于获取这些实体并使用LEFT OUTER JOIN来执行此操作。但是,如果尝试将默认获取类型设置为 FetchType.LAZY ,则连接类型将更改为 FetchMode.SELECT ,并且只为员工发出单一选择,而不选择主管。



设置 FetchType.LAZY @Fetch(FetchMode.JOIN)但是,会覆盖您的懒惰抓取并使用连接急切地抓取您的主管。


Suppose I have a table called employee with fields of employee_id, name and supervisor_id and employee_supervisor with fields of supervisor_id and name. There is a foreign key relationship the employee and employee_supervisor table with respect to the supervisor_id column.

If I do a many to one annotation mapping in the Employee class, how can I make sure that Hibernate uses a LEFT OUTER JOIN to join the associated entities?

解决方案

In my testing Hibernate did a LEFT OUTER JOIN by default. However you can ensure that it will always use a LEFT OUTER JOIN with annotations. I spent some time mocking up your situation using the bi-directional one to many mapping from my templates as a base, and then changing class names to match your situation.

The classes I came up with are as follows:

EmployeeSupervisor class:

@Entity(name="EMPLOYEE_SUPERVISOR")
public class EmployeeSupervisor {
    @Id
    @GenericGenerator(name = "gen", strategy = "increment")
    @GeneratedValue(generator = "gen")
    @Column(name = "id")
    private int supervisorId;

    @Column
    private String name;

    @OneToMany(mappedBy = "supervisor")
    private List<Employee> employees;
    ....
}

Employee class:

@Entity
public class Employee {
    @Id
    @GenericGenerator(name = "gen", strategy = "increment")
    @GeneratedValue(generator = "gen")
    @Column(name = "id")
    private int employeeId;

    @Column
    private String name;

    @ManyToOne
    @Fetch(FetchMode.JOIN)
    @JoinColumn(name = "supervisorId")
    private EmployeeSupervisor supervisor;
    ....
}

The annotation that ensures that you will always use a LEFT OUTER JOIN is the @Fetch(FetchMode.JOIN annotation. This tells Hibernate to load the associated record in the same select statement using a LEFT OUTER JOIN (see the documentation for the other types of FetchMode's and what each one does).

I then mocked up the database in jUnit, configured Hibernate to print all the generated SQL's in log4j

log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE

and ran a pretty basic unit test.

public class EmployeeDAOTest extends SpringTest{

    @Autowired
    private EmployeeDAO dao;

    private Employee testLinkedEmployee;
    private Employee testUnlinkedEmployee;
    private EmployeeSupervisor testSupervisor;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("Starting DAO Test");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        System.out.println("Finished DAO Test");
    }

    @Before
    public void setUp() throws Exception {
        //Irrelevant horrible setup code snipped.
        /* Set up 2 employees and a EmployeeSupervisor in the database.
         * Link one employee to the EmployeeSupervisor and not the other
         */
    }

    @Test
    @Transactional
    public void test() {
        Employee actualLinkedEmployee = dao.getEmployee(testLinkedEmployee.getEmployeeId());
        Employee actualUnlinkedEmployee = dao.getEmployee(testUnlinkedEmployee.getEmployeeId());

        assertNotNull("The linked employee's supervisor didn't get selected.", actualLinkedEmployee.getSupervisor());
        assertNull("The unlinked employee's supervisor was not null.", actualUnlinkedEmployee.getSupervisor());
    }
}

My DAO is exceedingly rudimentary:

@Repository
public class EmployeeDAOImpl implements EmployeeDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Employee getEmployee(int id) {
        Criteria query = sessionFactory.getCurrentSession().createCriteria(Employee.class);
        query.add(Restrictions.idEq(id));
        return (Employee) query.uniqueResult();
    }
}

and the SQL output is as follows:

[junit]     /* criteria query */ select
[junit]         this_.id as id1_1_1_,
[junit]         this_.name as name2_1_1_,
[junit]         this_.supervisorId as supervis3_1_1_,
[junit]         employeesu2_.id as id1_0_0_,
[junit]         employeesu2_.name as name2_0_0_ 
[junit]     from
[junit]         Employee this_ 
[junit]     left outer join
[junit]         EMPLOYEE_SUPERVISOR employeesu2_ 
[junit]             on this_.supervisorId=employeesu2_.id 
[junit]     where
[junit]         this_.id = ? 01:23:54:0.668 
[junit] binding parameter [1] as [INTEGER] - 5 01:23:54:0.671 

[junit]     /* criteria query */ select
[junit]         this_.id as id1_1_1_,
[junit]         this_.name as name2_1_1_,
[junit]         this_.supervisorId as supervis3_1_1_,
[junit]         employeesu2_.id as id1_0_0_,
[junit]         employeesu2_.name as name2_0_0_ 
[junit]     from
[junit]         Employee this_ 
[junit]     left outer join
[junit]         EMPLOYEE_SUPERVISOR employeesu2_ 
[junit]             on this_.supervisorId=employeesu2_.id 
[junit]     where
[junit]         this_.id = ? 01:23:54:0.704 
[junit] binding parameter [1] as [INTEGER] - 6 01:23:54:0.704 

It should be noted that by default Hibernate seems to be eagerly fetching these entities and uses a LEFT OUTER JOIN to do so. However if you try and set the default fetch type to be FetchType.LAZY then the join type changes to a FetchMode.SELECT and just issues a single select for the employee without selecting the supervisor as well.

Setting FetchType.LAZY with @Fetch(FetchMode.JOIN) however, overrides your lazy fetching and uses a join to eagerly fetch your supervisor.

这篇关于如何在使用@OneToOne和@OneToMany时创建Hibernate OUTER JOIN的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆