![](/img/trans.png)
[英]How to retrieve data from Hibernate bidirectional OneToMany ManyToOne in Java Spring
[英]Hibernate 5 Java bidirectional oneToMany field is null but table contains data
我有两个实体Department和Employee。 部门有员工清单。 员工有一个现场部门。 我可以创建员工并将其添加到部门内部的列表中。 数据库表将按预期的方式持久存储。 如果我查询一个部门,我会得到该部门,并填写员工名单。 这样一切都很好。 如果我查询Employee并获取Department字段,则返回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
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,则会得到所有的Employees。
我尝试了这里描述的两种方法: https : //docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch07.html#collections-bidirectional
示例7.21。 双向一对多,以一对多的身份作为关联所有者
和
示例7.22 与所有者一对多的双向关联
对我来说也是一样。
我想念什么?
这是完整的测试项目: 更新的项目zip
解决的固定项目: 解决的问题项目
看起来像一个Owning entity
问题,所以我认为您的测试以两种不同的方式持久化数据。 在注释@OneToMany(cascade = CascadeType.ALL)
您已声明Department
为该关系的所有者。 因此,如果您使用
dept.getEmployees().add(emp);
然后部门(id)字段将被更新
Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)
Hibernate: update EMPLOYEE set DEPARTMENT=? where EMP_ID=?
但是如果你坚持
emp.setDepartment(dept);
那么员工的部门(id)字段将不会更新。
Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)
如果雇员的部门编号未保留,则无法检索该部门。 如果使Employee为关系的所有者,则效率更高,因为它具有外键。
@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;
并在保持关系时设置员工的部门。 然后,使用部门编号完成插入,并且不会单独更新。
Hibernate: insert into EMPLOYEE (EMP_ID, DEPARTMENT, DESIGNATION, NAME) values (null, ?, ?, ?)
标准代码没有任何明显的错误,因为JPA将遵循带注释的关系,但是由于您没有特定的联接,因此它会在两个单独的查询中这样做。
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语句中完成。
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
我认为您的关系映射不正确! 尝试像这样更改代码。
@ManyToOne
@JoinColumn(name = "DEPT_ID")
private Department department;
@OneToMany(mappedBy = "department",cascade = CascadeType.ALL)
private List<Employee> employees = new ArrayList<>();
使用以下代码尝试一下,只需将联接表从Employee指向Department。
@ManyToOne
@JoinColumn(name = "DPT_ID", insertable = false, updatable = false)
private Department department;
我发现了问题。 我使用相同的会话进行访问和查询。
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.getTransaction();
transaction.begin();
…
session.persist(stuff);
session.flush();
transaction.commit();
transaction = session.getTransaction();
transaction.begin();
query stuff
如果我在坚持后关闭会话并打开一个新会话,则一切正常。
我添加了一个固定版本的测试项目到我的问题,以防万一有人被打扰了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.