当前位置: 首页 > 知识库问答 >
问题:

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

薛弘阔
2023-03-14

假设我有一个名为雇员的表,其字段为employee_idnamesupervisor_idemployee_supervisor,其字段为supervisor_idname雇员employee_supervisor表与supervisor_id列之间存在外键关系。

如果我在雇员类中执行多对一注释映射,如何确保Hibernate使用LEFT OUTER JOIN加入关联实体?

共有3个答案

龙浩博
2023-03-14

这完全取决于您的业务逻辑,也就是说,如果您希望拥有员工记录employee_supervisorid是强制性的,那么请使用内连接,否则请使用左连接。更多你可以在这里阅读:左连接和内连接的区别

堵远航
2023-03-14
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 
解阳泽
2023-03-14

在我的测试中,Hibernate默认使用了LEFT OUTER JOIN。但是,您可以确保它始终使用带有注释的LEFT OUTER JOIN。我花了一些时间来模拟你的情况,使用我模板中的双向一到多映射作为基础,然后改变类名来匹配你的情况。

我想出的类如下:

员工主管级别:

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

确保始终使用左外部联接的注释是@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]     /* 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似乎急切地获取这些实体,并使用左外部连接来实现。但是,如果尝试将默认获取类型设置为FetchType。LAZY然后连接类型更改为获取模式。选择,只为员工发出一个选择,而不选择主管。

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

 类似资料:
  • 问题内容: 我通过使用本教程学习Spring,Hibernate,Maven:Chad Lung:一个使用Netbeans 7,JUnit,Maven,HSQLDB,Spring和Hibernate的项目 。可以,但是我需要建立一对多关系(一个雇员有很多任务)。我已经尝试了许多示例,但仍然不知道如何使代码正常工作: Employee.java: Task.java: db-config.xml:

  • 问题内容: 我不了解左外部联接,右外部联接的概念,或者根本不理解为什么我们需要使用联接!我正在努力解决的问题以及正在处理的表格在这里:链接 问题3(b) 在SQL中构造命令以解决以下查询,解释了为什么必须使用(外部)联接方法。[5分]“找到每名工作人员及其his属(如果有)的姓名” 问题3(c)- 使用(i)join方法和(ii)子查询方法在SQL中构造命令以解决以下查询。[10分]“查找在计算机

  • 我有以下三个实体: 人 客户端具有个人id外键和区域id外键。一个人可以有很多客户,每个客户都属于一个地区。我正在尝试使用Laravel中的单个查询获取一个人的客户列表以及每个客户的区域。我曾经亲自与客户建立过很多关系,这很好。我正在尝试使用hasManyThrough方法来查询一个人,并获取他的客户和他们所在的地区,但我无法让它工作!我的关系设置为: 人有很多客户 客户属于区域 人已通过(客户,

  • 嗨,我正在尝试使用左外部连接执行hql查询,它是thwhing异常作为org.hibernate.hql.ast.querysyntaxException:意外标记:在第1行附近,可以告诉我这个查询中有什么问题吗 从CreditCardDetails cred左外连接CustomerHistory custHist on cred.creditCardDetailSid=custHist.Cred

  • 问题内容: 我刚刚开始阅读JPA,并且在休眠中的实现了解了细节。但是,在那之前继续开发,您能否帮助您阐明基本的qn。 何时 使用OneToOne如果实体管理器需要处理相关对象的持久性,则可以使用OneToOne。关键是,我始终可以在不指定oneToOne的情况下生活,但是我有责任管理这种关系并确保所引用的对象不处于过渡状态。这是真的? 何时使用或不使用ManyToOne 假设我正在定义Employ

  • 我的数据库技能有点生疏,所以对我来说学习Hibernate有点难。 我一直在阅读一对一、一对多和多对多,简而言之,这是我年轻时的理解: 一对一:-表A链接到表B中的另一行,表A中的行数必须等于表B中的行数。 一对多:-每家公司可以有很多员工。 多对多:-许多医生可以拥有/分享不同的病人。(无意双关语)。 假设我有以下表格,对于殡仪员客户模型 [id[pk]、全名(char)、年龄(int)、地址(