4

非常に単純な Hibernate の例でいくつかのエンティティ オブジェクトを設定しようとしています。私のデータベースは、「Departments」(ID、Name) と「Employees」(Id、DepartmentsId、FirstName、LastName) の 2 つのテーブルで構成されています。私の SQL クエリは、Employees を Departments に単純に左結合したものです。

Hibernate のドキュメントで指定されているように注釈を設定しましたが、エンティティをシリアル化しようとすると、Hibernate は無限ループに入り、最終的に StackOverFlowError 例外をスローします。私の別の質問に答えた人は、「Department」オブジェクトに「Employee」オブジェクトのセットが含まれているため、スタック オーバーフローが発生していると判断できました。各オブジェクトには、一連の「Employee」オブジェクトが含まれる「Department」オブジェクトなどが含まれます。等

このタイプの双方向の関係は、上記のリンクのドキュメントに従って合法であると想定されています (Department の「mappedBy」パラメーターは、Hibernate の手がかりになるはずです。また、以下のコードでコメントアウトされている「joinColumn」アノテーションを使用してみました) 、および私が読んだ他のことは、Hibernateがこの状況で無限ループに陥らないほどスマートであるはずであることを示していますが、私の例では機能していません。Department オブジェクトを Employee クラスから削除して、双方向の関係を一方向の関係に変更すると、すべてが正常に機能しますが、明らかに多くの機能が失われます。

また、古い 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;
}
}
4

2 に答える 2

7

一般に、エンティティをシリアル化しないでください。循環依存とプロキシはそれを難し​​くします。代わりに、送信する必要のあるデータをDTO(新しいデータ専用クラス)に手動で転送し、代わりにシリアル化する必要があります。怠惰なコレクションやプロキシなどはありません。

于 2012-04-22T08:22:29.757 に答える
0

トップの応答を補完するために、エンティティ値を DTO オブジェクトに転送する一般的な変換を行いました。マッピングされたエンティティから同じ名前の dto フィールドを作成するだけです。

これがソースコードです。

/** * Atribui os valores de campos expressentes de um object para um outro objeto de destino. Os * campos do object de destino que ja estiverem preenchidos nao serao substituidos * * @param objetoOrigem * @param objetoDestino * @return * @throws 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;
}
于 2016-04-29T13:53:49.707 に答える