Набор Hibernate @OneToMany теряет свой порядок при получении в конечной точке API

#java #json #hibernate #api #one-to-many

#java #json #спящий режим #API #один ко многим

Вопрос:

У меня возникли проблемы с получением упорядоченных данных в конечной точке java API из интерфейса react.

В частности, это массив JSON, который содержит внутри рекурсивно объекты и массивы в древовидной структуре, как в примере, написанном ниже

Вопрос: как я могу получить свой массив дочерних элементов, который отображается с помощью Hibernate внутри набора дочерних элементов, в правильном порядке? Вероятно, мне не хватает какой-то аннотации hibernate или чего-то еще

Если я перейду в режим отладки, я обнаружил, что сразу после ввода в первую строку кода метода savePeopleByDynastyId() набор дочерних элементов внутри PeopleList потерял порядок.

(правильный порядок, который я хочу достичь для объектов Person: child1, child2, child3)

Это единственный способ отправить их с и Id уже (я бы предпочел этого избежать)? Если да, какую аннотацию я должен добавить к @OneToMany private Set<Person> subChildren для достижения этой цели? Я пробовал @OrderBy(value = "id") , но это не работает

Любая помощь приветствуется!

Данные JSON, отправленные с помощью Postman для имитации запроса POST: http://localhost:8080/api/dynasty/people

   [
     {
      name: father,
      age: 50,
      subChildren : [
        {
            name: child1,
            age: 30,
            subChildren : []
        },
        {
            name: child2,
            age: 28,
            subChildren : []
        },
        {
            name: child3,
            age: 26,
            subChildren : []
        },
      ]
    }
  ]
 

Person.java:

 @Entity
@Table(name="Person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;


    private String name;
    private Integer age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="ID_PARENT")
    @JsonIgnore
    private Person parent;

    @OneToMany(mappedBy="parent", fetch = FetchType.EAGER)
    @OrderBy(value = "id")
    private Set<Person> subChildren  = new LinkedHashSet<Person>();
    
    public Person(){}

    //Getter and Setter
    
}
 

DynastyController.java:

 @RestController
@CrossOrigin
@RequestMapping("/api/dynasty")
public class DynastyController {

    @PostMapping("/people")
    public ResponseEntity<?> savePeopleByDynastyId(@RequestBody Iterable<Person> peopleList, BindingResult result){
        
        Iterable<Person> newPeopleList = null;
        for (Person person : peopleList) {
            //intention : cycle through each person of subChildren array recursively and persist each of his person 
        }
        ResponseEntity<Iterable<Person>> responseEntity= new ResponseEntity<>(newPeopleList, HttpStatus.CREATED);
        return responseEntity;
    }
}
 

Комментарии:

1. Идентификатор orderby не работает, возможно, потому, что у вас нет идентификатора в списке ответов. Попробуйте включить идентификатор в ответ и проверить.

2. спасибо за ответ. Я пробовал это с идентификатором в списке ответов, но это не сработало. Я не указывал id в вопросе, потому что я хотел бы найти решение без отправки id из интерфейса, потому что я считаю, что они должны быть сгенерированы на бизнес-уровне, когда объект сохраняется в БД

Ответ №1:

Я думаю, что проблема заключается в десериализации, выполненной Джексоном. Он заменяет коллекцию на обычную HashSet вместо добавления к существующей LinkedHashSet . Попробуйте использовать LinkedHashSet тип как объявленный тип в сущности.

Комментарии:

1. к сожалению, я не могу изменить набор в LinkedHashSet, потому что он не будет компилироваться, для Hibernate требуется: тип атрибута «От одного до многих» должен быть [java.util. Коллекция, java.util. Список, java.util.Set]

2. Вы проверяли, является ли тип набора все еще связанным набором хэшей после десериализации?

3. Путем отладки в вашем методе контроллера и проверки типа объекта переменной.

4. Я подтверждаю, что это HashSet, что я могу сделать?

5. Согласно документации Hibernate путем добавления аннотации @OrderBy, набор должен быть преобразован в LinkedHashSet, упорядоченный по указанному значению, поэтому вы говорите, что проблема в том, что перед тем, как действовать в режиме гибернации, Джексон десериализует массив JSON в HashSet