我想在一個非常簡單的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