Hibernate 5 Java双向oneToMany字段为空,但表包含数据 [英] Hibernate 5 Java bidirectional oneToMany field is null but table contains data

查看:70
本文介绍了Hibernate 5 Java双向oneToMany字段为空,但表包含数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个实体Department和Employee.部门有员工清单.员工有一个现场部门.我可以创建员工并将其添加到部门内部的列表中.数据库表将按预期的方式在持久性上填充.如果我查询一个部门,我会得到该部门,并填写员工名单".这样一切都很好.如果我查询Employee并获取Department字段,则返回null.

I have two entities Department and Employee. Department has a list of Employees. And Employee has a field Department. I can create Employees and add them to to list inside Department. The Database Tables are filled as expected on persist. If I query for a Department I get the Department and the List of Employees is filled. Everything fine this way. If I query for an Employee and get the Department field it Returns null.

@Entity
@Table(name = "DEPARTMENT")
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "DPT_ID")
    private long id;

    @Column(name = "NAME", nullable = false, unique = true)
    private String name;


    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "DEPARTMENT") //we need to duplicate the physical information
    private List<Employee> employees = new ArrayList<>();
…

-

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "EMP_ID")
    private long id;

    @Column(name = "NAME", nullable = false)
    private String name;

    @Column(name = "DESIGNATION")
    private String designation;

    @ManyToOne
    @JoinColumn(name = "DEPARTMENT", insertable = false, updatable = false)
    private Department department;
...

-

employee.getDepartment()返回null的查询

The query where employee.getDepartment() return null

        session = HibernateUtil.getSessionFactory().openSession();
        transaction = session.getTransaction();
        transaction.begin();

        Department department = new Department();
        department.setName("IT Department");

        Employee employee1 = new Employee();
        employee1.setName("Adam");
        employee1.setDesignation("Manager");

        Employee employee2 = new Employee();
        employee2.setName("Miller");
        employee2.setDesignation("Software Engineer");

        Employee employee3 = new Employee();
        employee3.setName("Smith");
        employee3.setDesignation("Associate  Engineer");

        department.getEmployees().add(employee1);
        department.getEmployees().add(employee2);
        department.getEmployees().add(employee3);

        session.persist(department);
        session.flush();
        transaction.commit();


        transaction = session.getTransaction();
        transaction.begin();

        {
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Employee> query = builder.createQuery(Employee.class);
            Root<Employee> root = query.from(Employee.class);
            query.select(root);
            Query<Employee> q = session.createQuery(query);
            List<Employee> employees = q.getResultList();
            for (Employee employee : employees) {
                System.out.println("EMPLOYEE NAME: " + employee.getName());
                System.out.println("DEPARTMENT NAME: " + employee.getDepartment()); // gives null
            }
        }
        {
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Department> query = builder.createQuery(Department.class);
            Root<Department> root = query.from(Department.class);
            query.select(root);
            Query<Department> q = session.createQuery(query);
            List<Department> departments = q.getResultList();
            for (Department deps : departments) {
                System.out.println(deps.getName());
                System.out.println(deps.getEmployees()); // list of employees is filled
            }
        }

表似乎已正确填充.但是,如果我在查询的Employee上使用getDepartment,我将得到null.如果我在查询的部门上使用getEmployees,则会得到所有雇员.

The tables seem to be filled correctly. But if i use getDepartment on a queried Employee i get null. If i use getEmployees on a queried Department i get all the Employees.

我尝试了以下两种方法:

I tried both ways described here : https://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch07.html#collections-bidirectional

示例7.21.双向一对多,多边作为协会所有者

Example 7.21. Bidirectional one to many with many to one side as association owner

示例7.22.拥有一对多方的双向关联

Example 7.22. Bidirectional association with one to many side as owner

对我来说结果相同.

我想念什么?

这是完整的测试项目:更新了项目zip

Here is the complete test Project: updated Project zip

已解决的固定项目:已解决的问题项目

推荐答案

看起来像是拥有实体的问题,所以我认为您的测试以两种不同的方式持久化数据.在注释 @OneToMany(cascade = CascadeType.ALL)中,您已声明 Department 为关系的所有者.因此,如果您使用

Looks like a Owning entity issue, so I think your test is persisting data in two different ways. In your annotation @OneToMany(cascade = CascadeType.ALL) you have declared Department to be the owner of the relationship. So, if you persist data with

dept.getEmployees().add(emp);

然后将更新部门(id)字段

then the department (id) field will be updated

Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)
Hibernate: update EMPLOYEE set DEPARTMENT=? where EMP_ID=?

但如果您坚持使用

emp.setDepartment(dept);

然后员工的部门(id)字段将不会更新.

then the department(id) field of employee won't get updated.

Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)

如果未保留员工的部门ID,则无法检索该部门.如果您使Employee为关系的所有者,则效率更高,因为它具有外键.

If the department id of employee isn't persisted then you can't retrieve the department. It's more efficient if you make Employee the owner of the relationship since it has the foreign key.

@OneToMany(cascade = CascadeType.ALL, mappedBy="department")
private List<Employee> employees; // don't need to make a list, only for fetches
// and 
@ManyToOne
@JoinColumn(name = "DEPARTMENT")
private Department department;

并在保持关系时设置员工的部门.然后使用部门编号完成插入,而不是单独进行更新.

and set the department of the employee when persisting relations. Then the insert is done with the departmentid and not updated separately.

Hibernate: insert into EMPLOYEE (EMP_ID, DEPARTMENT, DESIGNATION, NAME) values (null, ?, ?, ?)

标准代码没有任何明显的错误,因为JPA将遵循带注释的关系,但是由于您没有特定的联接,因此在两个单独的查询中会这样做.

There is nothing expressly wrong with the criteria code as JPA will follow the annotated relationship but it does so in two separate queries since you don't have a specific join.

Hibernate: select employee0_.EMP_ID as EMP_ID1_1_, employee0_.DEPARTMENT as DEPARTME4_1_, employee0_.DESIGNATION as DESIGNAT2_1_, employee0_.NAME as NAME3_1_ from EMPLOYEE employee0_
Hibernate: select department0_.DPT_ID as DPT_ID1_0_0_, department0_.NAME as NAME2_0_0_ from DEPARTMENT department0_ where department0_.DPT_ID=?

如果添加特定的提取,则它将在单个SQL语句中完成.

If you add a specific Fetch then it will do it in a single SQL statement.

root.fetch("department");

Hibernate: select employee0_.EMP_ID as EMP_ID1_1_0_, department1_.DPT_ID as DPT_ID1_0_1_, employee0_.DEPARTMENT as DEPARTME4_1_0_, employee0_.DESIGNATION as DESIGNAT2_1_0_, employee0_.NAME as NAME3_1_0_, department1_.NAME as NAME2_0_1_ from EMPLOYEE employee0_ inner join DEPARTMENT department1_ on employee0_.DEPARTMENT=department1_.DPT_ID

这篇关于Hibernate 5 Java双向oneToMany字段为空,但表包含数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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