假设我有一个名为employee
的表,其中包含employee_id
,name
和supervisor_id
字段,
employee_supervisor
字段为supervisor_id
和name
。 employee
和employee_supervisor
列相对于supervisor_id
列存在外键关系。
如果我在Employee
类中执行多对一注释映射,我如何确保Hibernate使用LEFT OUTER JOIN来加入关联实体?
答案 0 :(得分:2)
employee_supervisor{
id,
name
}
employee{
id,
name,
ManyToOne
supervisor_id
}
select supervisor FROM Employee e
left outer JOIN e.supervisor_id supervisor
WHERE e.id = :id
答案 1 :(得分:1)
在我的测试中,Hibernate默认执行了LEFT OUTER JOIN。但是,您可以确保始终使用带注释的LEFT OUTER JOIN。我花了一些时间使用my templates作为基础的双向一对多映射来模拟您的情况,然后更改类名以符合您的情况。
我提出的课程如下:
EmployeeSupervisor类:
@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;
....
}
员工类:
@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;
....
}
确保始终使用LEFT OUTER JOIN
的注释是@Fetch(FetchMode.JOIN
注释。这告诉Hibernate使用LEFT OUTER JOIN
在相同的select语句中加载相关记录(对于其他类型的FetchMode
,请参阅the documentation以及每个人做的事情)。< / p>
然后我在jUnit中模拟了数据库,配置了Hibernate来打印log4j中所有生成的SQL
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE
并进行了一次非常基本的单元测试。
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());
}
}
我的DAO非常简陋:
@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();
}
}
,SQL输出如下:
[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
应该注意的是,默认情况下,Hibernate似乎急切地获取这些实体并使用LEFT OUTER JOIN来执行此操作。但是,如果您尝试将默认提取类型设置为FetchType.LAZY
,则连接类型将更改为FetchMode.SELECT
,并且只为该员工发出一个选择,而不会选择主管。
然后使用FetchType.LAZY
设置@Fetch(FetchMode.JOIN)
,覆盖您的延迟抓取并使用联接来急切地获取您的主管。
答案 2 :(得分:0)
这完全取决于您的业务逻辑,意味着如果您希望拥有员工记录的employee_supervisor ID是强制性的,那么使用内部联接其他用于左联接。您可以在此处阅读更多内容:Difference between Left and Inner join