2016-11-19 3 views
2

Я хочу создать двунаправленное отношение учеников к дисциплине. Все работает нормально, пока я не зачислил пользователя на дисциплину. Теперь я получаю бесконечную рекурсию.Гибернайт бесконечной рекурсии цикла во многих отношениях

Классы выглядит следующим образом: появляется

//Student.java 
@Entity 
@Table(name = "students") 
public class Student { 
    @NotNull 
    @Id 
    @Column(name = "STUDENT_ID") 
    private String id; 
    private String name; 
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    @JoinTable(name = "students_disciplines", joinColumns = @JoinColumn(name = "STUDENT_ID"), inverseJoinColumns = @JoinColumn(name = "DISCIPLINE_ID")) 
    @JsonSerialize(using = NestedDisciplineSetSerializer.class) 
    private Set<Discipline> disciplines = new HashSet<>(); 
    //Getters, Setters 
} 
//NestedDisciplineSetSerializer.java 
public class NestedDisciplineSetSerializer extends JsonSerializer<Set<Discipline>> { 
    @Override 
    public void serialize(Set<Discipline> value, JsonGenerator jgen, SerializerProvider p) throws IOException, JsonProcessingException { 
     jgen.writeStartArray(); 
     for (Discipline s : value) { 
      jgen.writeStartObject(); 
      jgen.writeStringField("name", s.getName()); 
      jgen.writeNumberField("id", s.getId()); 
      jgen.writeBooleanField("recommended", s.isRecommended()); 
      jgen.writeEndObject(); 
     } 
     jgen.writeEndArray(); 
    } 
} 
//Discipline.java 
@Entity`enter code here` 
@Table(name = "disciplines") 
public class Discipline { 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Id 
    @Column(name = "DISCIPLINE_ID") 
    private int id; 
    @NotNull 
    private String name; 
    @NotNull 
    private int credits; 
    private String annotation; 
    private boolean recommended; 
    @ManyToMany(mappedBy = "disciplines", fetch = FetchType.EAGER) 
    @JsonSerialize(using = NestedStudentSetSerializer.class) 
    private Set<Student> students = new HashSet<>(); 
    //Getters, Setters 
} 
//NestedStudentSetSerializer.java 
public class NestedStudentSetSerializer extends JsonSerializer<Set<Student>> { 
    @Override 
    public void serialize(Set<Student> value, JsonGenerator jgen, SerializerProvider p) throws IOException, JsonProcessingException { 
     jgen.writeStartArray(); 
     for (Student s : value) { 
      jgen.writeStartObject(); 
      jgen.writeStringField("name", s.getName()); 
      jgen.writeStringField("id", s.getId()); 
      jgen.writeEndObject(); 
     } 
     jgen.writeEndArray(); 
    } 
} 

Ошибка будет при загрузке Set после Student s = sDao.findOne(id);

Пробовал искать здесь, но не смог найти правильное решение. Все получило тот же результат.

Error log

ответ

2

org.hibernate.collection.internal.PersistentSet.hashCode (PersistentSet.java:430) ~ [гибернации-ядро-5.0.11.Final.jar: 5.0.11.Final] в truelecter.practproekt .организация. Discipline.hashCode (Discipline.java:31) ~ [/ классы: Na] на java.util.HashMap.hash (HashMap.java:338) ~ [па: 1.8.0_91] в java.util. HashMap.put (HashMap.java:611) ~ [na: 1.8.0_91] at java.util.HashSet.add (HashSet.java:219) ~ [na: 1.8.0_91] at java.util.AbstractCollection. addAll (AbstractCollection.java:344) ~ [na: 1.8.0_91] at org.hibernate.collection.internal.PersistentSet.endRead (PersistentSet.java:327) ~ [hibernate-core-5.0.11.Final. jar: 5.0.11.Final] at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection (CollectionLoadContext.java:234) ~ [hibernate-core-5.0.11.Final.jar: 5.0.11.Final ] at ... org.hibernate.collection.internal.PersistentSet.hashCode (PersistentSet.java:430) ~ [hibernate-core-5.0.11.Final.jar: 5.0.11.Final] at truelecter.practproekt. организация. Student.hashCode (Student.java:29) ~ [classes /: na] at java.util.HashMap.hash (HashMap.java:338) ~ [na: 1.8.0_91] at java.util.HashMap .put (HashMap.java:611) ~ [na: 1.8.0_91] at java.util.HashSet.add (HashSet.java:219) ~ [na: 1.8.0_91] at java.util.AbstractCollection.addAll (AbstractCollection.java:344) ~

у меня создалось впечатление, что hashcode() реализации методов для Discipline и Student субъектов использовать как объекты.
Возможно, я ошибаюсь, это не очень понятно в stacktrace.
Как вы определили методы equals() и hashcode()?
Предположим, что объект A и предприятие B с двунаправленной связью.
Если equals()/hashcode() реализация объекта A вызывает equals()/hashcode() на сущности B поле, которое само по себе вызывает equals()/hashcode() на поле объект A, у вас есть цикл.
Принимая во внимание вашу ошибку.

Кроме того, даже если сократить цикл, гарантируя, что только один из обоих относится другой в equals()/hashcode()/toString(), вы должны вызвать equals()/hashcode()/toString методы отношений сущностей с осторожной.
Это может оказать реальное влияние на производительность. Если сеанс Hibernate открыт, он может действительно выполнять запросы, которых вы не ожидаете.

+0

Спасибо за ответ, проблема была в библиотеке ломбока, которую я использовал для упрощения генерации геттеров и сеттеров. Это @Data аннотация генерирует hashCode() метод для обоих объектов, которые создали цикл. – TrueLecter

+0

Добро пожаловать :) Спасибо за отзыв. – davidxxx

1

Обе стороны имеет нетерпеливый тип выборки. Это означает, что для каждого учащегося, который вы загружаете, Hibernate будет загружать каждую связанную с Дисциплиной, и для каждой Дисциплины он загрузит своих учеников. Это ваш цикл. Вы можете изменить тип выборки одной стороны (лучше обе), для FetchType.LAZY. При этом дисциплина студента будет загружаться, только когда вы получите доступ к списку.

Смежные вопросы