我想在一个非常简单的Hibernate示例中填充一些实体对象。我的数据库包含两个表,“部门”(Id,Name)和“Employees”(Id,DepartmentsId,FirstName,LastName)。我的SQL查询只是员工与部门的左连接。如何在获取双向集合时避免Hibernate中的无限循环?
我已经设置了Hibernate documentation中指定的注释,但每当我尝试序列化实体时,Hibernate会进入无限循环并最终抛出StackOverFlowError异常。有人回答我的另一个问题是能够确定发生堆栈溢出,因为“Department”对象包含一组“Employee”对象,每个对象都包含一个“Department”对象,其中包含一组Employee对象等。等
这种类型的双向关系应该是合法的,根据上面链接的文档(Department的“mappedBy”参数应该提示Hibernate在;我也尝试使用“joinColumn”注释被注释在下面的代码中)和其他我已经读过的东西指出休眠是假设足够聪明,在这种情况下不会陷入无限循环,但它不适用于我的示例。如果我通过从Employee类中移除Department对象将双向关系更改为单向关系,那么一切正常,但显然这会导致很多功能的丢失。
我也尝试了前面的旧XML映射文件的注释,并为子表设置“反向”参数,但它仍然会产生相同的问题。我如何才能使这种双向关系按照它应该工作的方式工作?
部:
package com.test.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.JoinTable;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.JoinColumn;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
@Entity
@Table(name="Departments"
,catalog="test"
)
public class Department implements java.io.Serializable {
private Integer id;
private String name;
public Set<Employee> employees = new HashSet<Employee>(0);
public Department() {
}
public Department(String name) {
this.name = name;
}
public Department(String name, Set employees) {
this.name = name;
this.employees = employees;
}
@Id @GeneratedValue(strategy=IDENTITY)
@Column(name="Id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="Name", nullable=false)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch=FetchType.LAZY, mappedBy="department")
/*@OneToMany
@JoinColumn(name="DepartmentsId")*/
public Set<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(Set employees) {
this.employees = employees;
}
}
员工:
package com.test.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.JoinTable;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="Employees"
,catalog="test"
)
public class Employee implements java.io.Serializable {
private Integer id;
private Department department;
private String firstName;
private String lastName;
public Employee() {
}
public Employee(Department department, String firstName, String lastName) {
this.department = department;
this.firstName = firstName;
this.lastName = lastName;
}
@Id @GeneratedValue(strategy=IDENTITY)
@Column(name="Id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name="DepartmentsId", nullable=false, insertable=false, updatable=false)
public Department getDepartment() {
return this.department;
}
public void setDepartment(Department department) {
this.department = department;
}
@Column(name="FirstName", nullable=false)
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name="LastName", nullable=false)
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
部经理(包含HQL查询):
package com.test.controller;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import com.test.model.Department;
import com.test.util.HibernateUtil;
public class DepartmentManager extends HibernateUtil {
public List<Department> list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List<Department> set = null;
try {
Query q = session.createQuery("FROM Department d JOIN FETCH d.employees e");
q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
set = (List<Department>) q.list();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.getTransaction().commit();
return set;
}
}
是否有该证明的代码会导致异常,还是仅仅在序列化期间?因为如果只是在序列化过程中才有意义。这是因为在序列化期间,每个实体都充当代理。如果你要采用一个部门并说“给我的员工”,那么对于每个员工你会说“给我部门”,然后为每个部门说“给我员工”......我预计堆栈溢出。在黑暗中刺,但如果你序列化为JSON,那就是struts2-json-plugin。该序列化程序提供包含和排除参数。 – Quaternion 2012-04-22 05:56:41
这会让你修剪树木,在你想要的深度处将它挡住。在你提供的关系的情况下,参数可以为了不同的目的修剪树,因此这个单个查询可以最好由几个不同的动作来表示。 – Quaternion 2012-04-22 06:01:50
我相信这个例外只是在序列化过程中,所以你说的是有道理的。我使用XSLT结果,而不是JSON,但挂断可能是相同的。 Struts2曾经提供了一些包含/排除模式,但是这个功能在某个时候被打破了,并且从未被修复过。它提供了一个使用OGNL表达式的“exposedValue”参数,但我从来没有得到它的工作权利(我可以用“[0] .departmentsList指定部门对象的列表,但不能让它指定特定的领域,如”[0 ] .departmentsList.id。“也许我将不得不去DOT路线Bozho下面提到。 – 2012-04-22 10:24:00