javaspring-bootspring-data-jpaforeign-keysone-to-many

Update with CrudRepository save() alter the order of multiple fileds and changing they ID


I have a problem when i try to update a questionary from a json. I need to store some data in db from a json. I use multiple entity for set the questionary and some @onetomany for create foreignkey.

The first time i store the data all is good, hibernate store correctly all the data whit autogenerated id, when i try to load again a json whit some changes on the child table, the id of the Questionary persist correctly (becouse is a field obteined dircetly from json) the questions and answer change id though i set the values.

I hope you undrestand what i mean.

this is my entity:

public class Questionary implements Serializable {

    private static final long serialVersionUID = -6101283729971360969L;
    /**
     * Primary key from JSON
     */
    @Id 
    @JsonIgnore
    private int id;
    @Version
    private Long version;
    private String desc;
    

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name = "idQuest")
    @OnDelete(action = OnDeleteAction.CASCADE)
    @OrderBy("identityQuestion ASC")
    private Set<Question> question;

public class Question implements Serializable {

private static final long serialVersionUID = -6101283729971360969L;
@Id 
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
@Version
private Long version;
private int identityQuestion;
private String text;
private long idTipoTag;

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name = "idQuestion")
@OnDelete(action = OnDeleteAction.CASCADE)
@OrderBy("identityAnswer ASC")
private Set<Answer> answer;

this is the method on controller

@RestController
@Slf4j
public class QuestionaryController {

@Autowired
private QuestionaryRepository questionaryRepository;
@Autowired
private AnswerRepository answerRepository;

@RequestMapping(value = "/save", method = RequestMethod.POST)
public void saveQuest(@RequestBody List<QuestionaryDTO> questDTO) {

    for (QuestionaryDTO questionaryDTO : questDTO) {

        /**
         * find value in db
         */
            Questionary quest = questionarioRepository.findById(questionarioDTO.getId());
            if (quest != null) {
                
                quest.setDescrizione(questionarioDTO.getDescrizione());
                
                Set<QuestionDTO> listQuestion = QuestionaryDTO.getQuestion();
                Set<Question> questionDB = quest.getQuestion();
                
                ArrayList<QuestionDTO> l = new ArrayList<QuestionDTO>(listQuestion);
                ArrayList<Question> c = new ArrayList<Question>(questionDB);
                
                int i = -1;
                for(int j=0; j<l.size();j++) {
                     
                    i++;
                    Question dom = c.get(i);                
                    dom.setIdentityQuestion(l.get(j).getId());
                    dom.setIdTipoTag(l.get(j).getIdTipoTag());
                    dom.setText(l.get(j).getText());
                    questionDB.add(dom);
                    
                        ecc...
        
                }
                quest.setquestion(questionDB);
                questionariyRepository.save(quest);
              
            } else {
        
    
            /**
             * Questionary
             */
            Questionary questn = new Questionary();
            questn.setTitle(questionaryDTO.getTitle()); 
            questn.setId(questionaryDTO.getId());
            /**
             * Questions
             */
            Set<QuestionDTO> listQuestion = questionaryDTO.getQuestion();
            Set<Question> QuestionDB = new HashSet<>();
            for (QuestionDTO questionDTO : listQuest) {
                Question que = new Question();
                que.setIdentityQuestion(questionDTO.getId());
                que.setText(QuestionDTO.getText());
                que.setIdTipoTag(QuestionDTO.getIdTipoTag());
                QuestionDB.add(que);
                /**
                 * Answers
                 */
                Set<AnswerDTO> listAnswers = AnswerDTO.getAnswers();
                Set<Answers> listAnswersDB = new HashSet<>();

                for (AnswersDTO AnswersDTO : listAnswer) {
                    Answers ans = new Answers();
                    ans.setIdentityAnswer(AnswerDTO.getId());
                    asn.setText(AnswerDTO.getText());
                    listAnswersDB.add(ans);
                }
                dom.setAnswer(listAnswersDB);
            }
            questn.setQuestion(QuestionDB);
            questionarioRepository.save(questn);
            }
        }
    }

This is DTO entity

public class QuestionariyDTO implements Serializable{

    private static final long serialVersionUID = -1886966747159529916L;
    private int id;
    private int identityQuestionary;
    private String title;
    private Set<QuestionDTO> questions;
    
}

public class QuestionDTO implements Serializable {

    private static final long serialVersionUID = -1886966747159529916L;
    private int id;
    private String text;
    private Long idTipoTag;
    private Set<AnswerDTO> answers;
}

public class AnswerDTO implements Serializable{
    
    private static final long serialVersionUID = -1886966747159529916L;
    private Long id;
    private String text;
    private Long identityAnswer;
}

this in an example of json structure

    [
    {
        "id": 1,
        "title": "TITLE",
        "questions": [
            {
                "id": 1, <--- this id is only "identityQuestion" on db is not the primary key
                "text": "some text",
                "idTipoTag": 1,
                "answers": [
                    {
                        "id": 1, <--- this id is only "identityAnswer" on db is not the primary key
                        "text": "answ 1"
                    },
                    {
                        "id": 2,
                        "text": "answ 2"
                    },
                    {
                        "id": 3,
                        "text": "answ 3"
                    },
                    {
                        "id": 4,
                        "text": "answ 4"   
                    }
                    ]
            },
            {
                "id": 2,
                "text": "some text",
                "idTipoTag": 1,
                "answers": [
                    ...
                    
                    .
                    
                    .
                    .
                    .
                    .
                    ]
            },
...
        ]
    }
]

Solution

  • The cause of save in random order is the HashSet, they don't have a order and always save date in random position.

    I have just converted all the Set value into List. After do it when i go to instance the object i use a LinkedList for order value!

    this works smooth for me!

    here is an example:

    Before:

    Set<QuestionDTO> listQuestion = questionaryDTO.getQuestion();
    Set<Question> QuestionDB = new HashSet<>();
    

    After:

    List<QuestionDTO> listQuestion = questionaryDTO.getQuestion();
    List<Question> QuestionDB = new LinkedList<>();