在获取双向集合时如何避免Hibernate中的无限循环?

J E*_*lis 4 java hibernate struts2

我试图在一个非常简单的Hibernate示例中填充一些实体对象.我的数据库由两个表组成,"部门"(Id,Name)和"Employees"(Id,DepartmentsId,FirstName,LastName).我的SQL查询只是Employees与Departments的左连接.

我已经设置了Hibernate文档中指定的注释,但每当我尝试序列化实体时,Hibernate进入无限循环并最终抛出StackOverFlowError异常.回答我的另一个问题的人能够确定堆栈溢出正在发生,因为"Department"对象包含一组"Employee"对象,每个对象都包含一个"Department"对象,其中包含一组Employee对象等.等等

根据上面链接的文档,这种类型的双向关系应该是合法的(Department中的"mappedBy"参数应该用来表示Hibernate;我也尝试使用在下面的代码中注释掉的"joinColumn"注释)我读过的其他内容表明Hibernate 应该足够聪明,不要在这种情况下进入无限循环,但它不适用于我的例子.如果我通过从Employee类中删除Department对象将双向关系更改为单向关系,一切正常,但显然这会导致丢失大量功能.

我还尝试了旧的xml映射文件的注释,并为子表设置了"inverse"参数,但它仍然会产生同样的问题.我怎样才能使这种双向关系按照预期的方式运行?

部门:

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;
}
}
Run Code Online (Sandbox Code Playgroud)

雇员:

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;
}
}
Run Code Online (Sandbox Code Playgroud)

部门经理(包含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;
}
}
Run Code Online (Sandbox Code Playgroud)

Boz*_*zho 7

通常,您不应序列化您的实体.循环依赖和代理使得这很难.相反,您应手动将需要发送的数据传输到DTO(新的仅数据类),并将其序列化.它不会有懒惰的集合,代理和诸如此类的东西.