使用@OneToOne和@OneToMany时,如何使Hibernate外部联接

使用@OneToOne和@OneToMany时,如何使Hibernate外部联接,hibernate,Hibernate,假设我有一个名为employee的表,其中包含employee\u id、name和supervisor\u id字段,以及 employee\u supervisor,字段为supervisor\u id和name。关于主管id列,在员工和员工_主管表中存在外键关系 如果我在Employee类中进行多对一注释映射,如何确保Hibernate使用左外部联接来联接关联的实体?这完全取决于您的业务逻辑,这意味着如果Employee\u supervisor id必须有员工记录,然后使用内部联接,否则

假设我有一个名为
employee
的表,其中包含
employee\u id
name
supervisor\u id
字段,以及
employee\u supervisor
,字段为
supervisor\u id
name
。关于
主管id
列,在
员工
员工_主管
表中存在外键关系


如果我在
Employee
类中进行多对一注释映射,如何确保Hibernate使用左外部联接来联接关联的实体?

这完全取决于您的业务逻辑,这意味着如果Employee\u supervisor id必须有员工记录,然后使用内部联接,否则使用左联接。您可以在这里阅读更多信息:

在我的测试中,Hibernate默认情况下进行了左外部连接。但是,您可以确保它始终使用带注释的左外部联接。我花了一些时间模拟您的情况,使用双向一对多映射作为基础,然后更改类名以匹配您的情况

我提出的课程如下:

员工主管级别:

@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;
    ....
}
确保始终使用
左外部联接的注释是
@Fetch(FetchMode.JOIN
注释。这告诉Hibernate使用
左外部联接在同一select语句中加载相关记录(请参阅其他类型的
FetchMode
,以及每种类型的作用)

然后,我在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());
    }
}
我的刀非常简陋:

@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]/*条件查询*/select
[junit]此.id作为id1_1_1_,
[junit]此名称为name2_1_1_,
[junit]这个监管者被称为监管者,
[junit]employeesu2.id作为id1\u 0\u 0\u,
[junit]employeesu2。名称为name2\u 0\u 0\u
[junit]来自
[junit]这名员工
[junit]左外连接
[junit]员工、主管、员工
[junit]在这个u.supervisorId=employeesu2_uu.id上
[朱尼特]在哪里
[junit]this_u.id=?01:23:54:0.668
[junit]绑定参数[1]为[INTEGER]-5 01:23:54:0.671
[junit]/*条件查询*/select
[junit]此.id作为id1_1_1_,
[junit]此名称为name2_1_1_,
[junit]这个监管者被称为监管者,
[junit]employeesu2.id作为id1\u 0\u 0\u,
[junit]employeesu2。名称为name2\u 0\u 0\u
[junit]来自
[junit]这名员工
[junit]左外连接
[junit]员工、主管、员工
[junit]在这个u.supervisorId=employeesu2_uu.id上
[朱尼特]在哪里
[junit]这个u2; id=?01:23:54:0.704
[junit]绑定参数[1]为[INTEGER]-6 01:23:54:0.704
需要注意的是,默认情况下,Hibernate似乎急切地获取这些实体,并使用左外部联接来实现。但是,如果尝试将默认获取类型设置为
FetchType.LAZY
,则联接类型将更改为
FetchMode。选择
,只为员工发出一个SELECT,而不选择sup埃尔维索也是


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

这取决于您的代码。发布它。在您进行操作时,只需将Hibernate配置为记录其SQL语句并读取它们,您就会得到答案。感谢您的回答。我已经登录了。目前它正在进行内部连接。但我nt将其作为左外联接。为此,我必须在代码中更改什么?我们不能在不查看代码的情况下决定更改什么。我们不是超清晰的向导。只有开发人员。@user2470454我提到了查询,它对您有帮助吗。非常感谢Arpit。在员工记录中,主管id不能为空。这就是为什么我希望它作为左外联接oin.但目前它正在进行内部连接。那么我必须做哪些更改?请您帮助我退出此链接,它将帮助您:
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());
    }
}
@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();
    }
}