Hibernate рекурсивное отображение родительской / дочерней структуры - StackruError при извлечении данных
Я использую Hibernate 5.2.7.Final и родной Hibernate API. У меня есть объект Employee с рекурсивными отношениями:
@Entity
public class Employee {
@Id
@GeneratedValue
private Long employeeId;
@Column
private String firstname;
@Column
private String lastname;
@ManyToOne(cascade={ CascadeType.ALL})
@JoinColumn(name="manager_id")
private Employee manager;
@OneToMany(mappedBy="manager", cascade = CascadeType.ALL)
private Set<Employee> subordinates = new HashSet<Employee>();
// setters, getters, constructors
}
Следующая таблица создана hibernate:
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| employeeId | bigint(20) | NO | PRI | NULL | |
| firstname | varchar(255) | YES | | NULL | |
| lastname | varchar(255) | YES | | NULL | |
| manager_id | bigint(20) | YES | MUL | NULL | |
+------------+--------------+------+-----+---------+-------+
Я успешно работаю менеджером и сотрудниками с:
Employee manager = new Employee("A", "B");
Employee employee1 = new Employee("C", "D");
Employee employee2 = new Employee("E", "E");
employee1.setManager(manager1);
employee2.setManager(manager1);
Set<Employee> employees = new HashSet<>();
employees.add(employee1);
employees.add(employee2);
manager.setSubordinates(employees);
session.save(manager);
Теперь получение сотрудника вызовет StackOverFlowError.
Long id = manager.getEmployeeId();
Query<Employee> query = ss.createQuery("from Employee e where e.employeeId = :employeeId", Employee.class);
query.setParameter("employeeId", id);
Employee retrieved = (Employee) query.uniqueResult();
Исключение в потоке "основной" java.lang.StackruError
at java.lang.Long.toString(Long.java:396)
at java.lang.Long.toString(Long.java:1032)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
Я думаю, что способ сохранения такого графа объектов Employee очень удобен. Но я понятия не имею, как извлечь такой график из таблицы.
Вопрос: как я могу осмысленно получить информацию о сотруднике из базовой таблицы. Я думаю, что можно обойти это, создав новую сущность для просмотра таблицы Employee, например
public class EmployeeView {
private Long employeeId;
private String firstname;
private String manager_name;
private Set<String> subordinate_names;
}
Могу ли я достичь этого? а как с аннотацией JPA?
1 ответ
Я подозреваю, что проблема заключается в toString()
метод в вашем Employee
юридическое лицо.
Так как вы не предоставили никакого кода, вот ясный пример того, как это могло бы произойти в более обобщенной перспективе Parent
а также Child
,
public class Parent {
@OneToMany(mappedBy = "parent");
List<Child> children;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append( "Parent{children=" );
children.forEach( sb::apend );
sb.append( "}" );
return sb.toString();
}
public class Child {
@ManyToOne
private Parent parent;
@Override
public String toString() {
return "Child{parent=" + parent + "}";
}
}
Теперь где-то в коде есть это:
System.out.println( parent.toString() );
Это вызвало бы ту же проблему переполнения, потому что вызов в Parent
будет делегировать вниз в Child
который делегирует обратно Parent
и неприятный цикл продолжается.
Вам нужно решить, какой из них наиболее логичен в вашем случае и, вероятно, либо пропустить, либо только распечатать идентификатор связанной сущности, чтобы избежать этого рекурсивного цикла.