非常に単純なHibernateの例で、いくつかのエンティティオブジェクトを設定しようとしています。私のデータベースは「部署」(Id、Name)と「従業員」(Id、DepartmentsId、FirstName、LastName)の2つのテーブルで構成されています。私のSQLクエリは、EmployeesとDepartmentsの左結合です。双方向コレクションをフェッチする際のHibernateでの無限ループを避けるには?
Hibernate documentationで指定された注釈を設定しましたが、エンティティをシリアル化しようとするたびに、Hibernateは無限ループに入り、最終的にStackOverFlowError例外をスローします。私の別の質問に答える誰かが、 "Department"オブジェクトにEmployeeオブジェクトのセットを含む "Department"オブジェクトを含む "Employee"オブジェクトのセットが含まれているため、スタックオーバーフローが発生していると判断できました。
このタイプの双方向関係は、上にリンクされたドキュメントの通りです(Departmentの "mappedBy"パラメータはHibernateを手がかりにしていると思います)、私はコメントされている "joinColumn"アノテーションを使ってみました私が読んだその他のことは、と仮定してがこの状況で無限ループにならないほどスマートであると仮定していますが、私の例では機能しません。 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;
}
}
従業員:
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;
}
}
が示されたのいずれかをい@throwsコードは例外を引き起こすか、まさに直列化中ですか?ので、それはちょうどセットのシリアル化の間に意味がある場合。これは、シリアライズ中に各エンティティがプロキシとして機能するためです。あなたが部門を取って「私に従業員を譲りたい」と言ったら、各従業員は「私に部門を教えてください」と言っていたのですが、部門ごとに「私に従業員をください」と言います...私はスタックオーバーフロー。暗闇の中で刺すが、JSONにシリアル化している場合は、struts2-json-pluginがある。このシリアライザには、includeパラメータとexcludeパラメータが用意されています。 – Quaternion
これは、木を剪定して、あなたが望む深さでそれをブロックすることができます。あなたが指定した関係の場合、パラメータはさまざまな目的のためにツリーを刈り込むことができます。したがって、この単一のクエリはいくつかの異なるアクションによって最もよく表現されます。 – Quaternion
私は例外がシリアライゼーションの間だけであると信じています。 JSONではなくXSLTの結果を使用しますが、ハングアップはおそらく同じです。 Struts2はいくつかのインクルード/エクスクルードパターンを提供していましたが、その機能はある時点で壊れており修正されていませんでした。 OGNL式を使って "exposedValue"パラメータを提供していますが、正しく動作することはありませんでした( "[0] .departmentsList"でDepartmentオブジェクトのリストを指定できますが、 "[0 ] .departmentsList.id。 "おそらく、Bozhoが以下に言及しているDTOルートに行く必要があります。 –