当前位置: 首页 > 知识库问答 >
问题:

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

单于楚
2023-03-14

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

我已经按照Hibernate文档中的规定设置了注释,但每当我尝试序列化实体时,Hibernate就会进入一个无休止的循环,并最终引发StackOverflowerError异常。回答我的另一个问题的人能够确定堆栈溢出正在发生,因为“Department”对象包含一组“Employee”对象,每个对象包含一个“Department”对象,其中包含一组Employee对象等。

这种类型的双向关系应该是合法的,正如上面链接的留档所示(“部门”中的“映射者”参数应该是Hibernate的线索;我还尝试过使用下面代码中注释掉的“joinCol列”注释),我读过的其他东西表明Hibernate应该足够聪明,不会在这种情况下进入无休止的循环,但它不适用于我的示例。如果我通过从员工类中删除部门对象将双向关系更改为单向关系,一切都会正常工作,但显然这会导致大量功能的丢失。

我还尝试过放弃旧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;
}
}

共有2个答案

阳念
2023-03-14

为了补充顶部的响应,我做了一个通用转换,由谁来为我做这项工作,将实体值传输到DTO对象,您只需使用映射实体中的相同名称来创建DTO字段。

这是源代码

/***阿贡蒂os valore de campos通讯员de um Objetto para um outro Objetto de Destino。os*campos do Objetto de Destino que ja一人一天一次替代idos**@参数ObjetoOrigem*@参数ObjetoDestino*@返回*@抛出NegocioException*/

public static <T1, T2> T2  convertEntity(T1 objetoOrigem, T2 objetoDestino) throws NegocioException {

    if (objetoOrigem != null && objetoDestino != null) {
        Class<? extends Object> classe = objetoOrigem.getClass();
        Class<? extends Object> classeDestino = objetoDestino.getClass();

        Field[] listaCampos = classe.getDeclaredFields();
        for (int i = 0; i < listaCampos.length; i++) {
            Field campo = listaCampos[i];
            try {
                Field campoDestino = classeDestino.getDeclaredField(campo.getName());
                campo.setAccessible(true);
                campoDestino.setAccessible(true);
                atribuiValorAoDestino(objetoOrigem, objetoDestino, campo, campoDestino);
            } catch (NoSuchFieldException e) {
                LOGGER.log(Logger.Level.TRACE, (Object) e);
                continue;
            } catch (IllegalArgumentException | IllegalAccessException e) {
                LOGGER.error(e.getMessage(), e);
                throw new NegocioException(e.getMessage(), EnumTypeException.ERROR);
            }
        }
    }
    return objetoDestino;
}
贲绪
2023-03-14

一般来说,您不应该序列化您的实体。循环依赖和代理使这变得困难。相反,您应该手动将您需要发送的数据传输到DTO(一个新的仅限数据的类),并将其改为序列化。它不会有惰性集合、代理等。

 类似资料:
  • 我有以下实体: 我尝试过创建@OneToOne(FetchType.lazy),但不起作用,它仍然提取不需要的信息。 如何避免获取复合对象? 我希望最终结果不包含Address对象,因为它在20个场景中需要一次,我可以分别获取它们。 任何想法,如何实现这一点。 谢谢

  • 问题内容: 我有一个我认为应该很普遍的问题,但找不到答案。 我有2个对象:组和用户。我的课程如下所示: 现在,当我尝试从数据库中获取用户时,它带来了所有组,所有组都带来了所有用户,依此类推。最后,我遇到了stackoverflow异常。 如何解决此问题,并且仍然具有双向关联以及到达列表中对象的能力? 问题答案: 如果使用属性(无论如何都应使用)将双向关联的一侧设为关联的 拥有 侧,是否会遇到相同的

  • 此特定环境下的程序:EJB3.0 JPA jersey Web Service 第一个实体: 第二实体: 当我拿到班级考试的学生名单时。例外情况是: 如果我更改fetch FetchType。懒惰例外情况是: 如何解决我的问题?

  • 问题内容: 我知道python中的循环导入问题已经出现过很多次了,我已经阅读了这些讨论。在这些讨论中反复提出的意见是,循环导入表明设计不良,应重新组织代码以避免循环导入。 有人可以告诉我在这种情况下如何避免循环导入吗?:我有两个类,并且我希望每个类都有一个构造函数(方法),该构造函数接受另一个类的实例并返回该类的实例。 更具体地说,一类是可变的,一类是不变的。哈希,比较等需要不可变的类。可变类也需

  • 我在服务器日志中收到一个警告“firstResult/max结果指定集合获取;在内存中应用!”。然而一切正常。但我不想要这个警告。

  • 但是这两种方法都不起作用(第一种方法导致ParseeRoreXception,第二种方法在传递给方法的值中产生双反斜杠)。