3 回答

TA貢獻1834條經(jīng)驗 獲得超8個贊
questionChoices
您正在JSON 正文中發(fā)送一個字符串數(shù)組。List<Question>
您的 JSON 映射器需要從該字符串數(shù)組中填充 a 。所以它需要將每一個都轉化String
為一個QuestionChoice
對象。據(jù)推測,它是通過調用QuestionChoice
以 aString
作為參數(shù)的構造函數(shù)來實現(xiàn)的。
因此,您正在保存一個Question
其中QuestionChoices
所有屬性都為空的question
屬性。因此,您告訴 JPA 所有 QuestionChoices 都沒有任何問題(因為它為空)。因此,JPA 會保存您告訴它保存的內容:QuestionChoices,而沒有任何父問題。
您需要正確question
初始化QuestionChoice
.

TA貢獻1826條經(jīng)驗 獲得超6個贊
反序列化器將始終使用默認構造函數(shù)來構造對象。您的自定義構造函數(shù)對反序列化沒有影響。
你能做的是:
1 - 保證服務/控制器層中的關聯(lián)
@PostMapping("/question")
public Question createQuestion(@RequestBody Question question) {
question.getQuestionChoices().forEach(choice -> choice.setQuestion(question));
return questionRepository.save(question);
}
或 2 - 保證 setter 方法中的關聯(lián):
public class Question {
// omitted for brevity
@OneToMany(mappedBy = "question", cascade = CascadeType.ALL)
private List<QuestionChoice> questionChoices;
public void setQuestionChoices(List<QuestionChoice> questionChoices) {
if (questionChoices != null) {
questionChoices.forEach(choice -> choice.setQuestion(this));
}
this.questionChoices = questionChoices;
}
}
更新
為了防止無限遞歸,只需從“questionChoice”中刪除“question”屬性以進行演示。
我可以想到兩個選擇:
1 - 將question內部設置為 nullquestionChoice
@PostMapping("/question")
public Question createQuestion(@RequestBody Question question) {
Question savedQuestion = questionRepository.save(question);
savedQuestion.getQuestionChoices().forEach(choice -> choice.setQuestion(null));
return savedQuestion;
}
@GetMapping("/question")
public List<Question> getQuestions() {
List<Question> questions questionRepository.findAll();
questions.forEach(question -> {
question.getQuestionChoices.forEach(choice -> choice.setQuestion(null));
});
return questions;
}
這會將您的問題選擇和外鍵保存到數(shù)據(jù)庫中,但questionChoices.question在發(fā)送響應時將序列化為 null 以防止無限遞歸。
2 - 使用 DTO。
您創(chuàng)建 DTO 將它們序列化為響應對象,以準確返回您想要的內容。
QuestionDTO.java
public class QuestionDTO {
private int question_id;
private String questionName;
private String questionText;
// notice that here you're using composition of DTOs (QuestionChoiceDTO instead of QuestionChoice)
private List<QuestionChoiceDTO> questionChoices;
// constructors..
// getters and setters..
}
QuestionChoiceDTO.java
public class QuestionChoiceDTO {
private int id;
private String choice;
// notice that you don't need to create the Question object here
// constructors..
// getters and setters..
}
然后在你的控制器中:
@PostMapping("/question")
public QuestionDTO createQuestion(@RequestBody Question question) {
Question savedQuestion = questionRepository.save(question);
List<QuestionChoiceDTO> questionChoices = new ArrayList<>();
savedQuestion.getQuestionChoices().forEach(choice -> {
questionChoices.add(new QuestionChoiceDTO(choice.getId(), choice.getChoice()));
});
QuestionDTO response = new QuestionDTO(savedQuestion.getQuestion_id(), savedQuestion.getQuestionName(), savedQuestion.getQuestionText(), questionChoices);
return response;
}
@GetMapping("/question")
public List<QuestionDTO> getQuestions() {
List<Question> questions = questionRepository.findAll();
List<QuestionDTO> response = new ArrayList<>();
questions.forEach(question -> {
List<QuestionChoicesDTO> questionChoices = new ArrayList<>();
question.getQuestionChoices().forEach(choice -> questionChoices.add(new QuestionChoiceDTO(choice.getId(), choice.getChoice()));
responses.add(new QuestionDTO(savedQuestion.getQuestion_id(), savedQuestion.getQuestionName(), savedQuestion.getQuestionText(), questionChoices));
});
}
我總是更喜歡后者,因為對于大型項目,恕我直言,使用 DTO 可以成為組織代碼和簡潔使用請求/響應對象而不使用域對象的強大工具。
添加回答
舉報