3 回答

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

TA貢獻(xiàn)1826條經(jīng)驗(yàn) 獲得超6個(gè)贊
反序列化器將始終使用默認(rèn)構(gòu)造函數(shù)來構(gòu)造對(duì)象。您的自定義構(gòu)造函數(shù)對(duì)反序列化沒有影響。
你能做的是:
1 - 保證服務(wù)/控制器層中的關(guān)聯(lián)
@PostMapping("/question")
public Question createQuestion(@RequestBody Question question) {
question.getQuestionChoices().forEach(choice -> choice.setQuestion(question));
return questionRepository.save(question);
}
或 2 - 保證 setter 方法中的關(guān)聯(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”屬性以進(jìn)行演示。
我可以想到兩個(gè)選擇:
1 - 將question內(nèi)部設(shè)置為 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;
}
這會(huì)將您的問題選擇和外鍵保存到數(shù)據(jù)庫中,但questionChoices.question在發(fā)送響應(yīng)時(shí)將序列化為 null 以防止無限遞歸。
2 - 使用 DTO。
您創(chuàng)建 DTO 將它們序列化為響應(yīng)對(duì)象,以準(zhǔn)確返回您想要的內(nèi)容。
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));
});
}
我總是更喜歡后者,因?yàn)閷?duì)于大型項(xiàng)目,恕我直言,使用 DTO 可以成為組織代碼和簡潔使用請(qǐng)求/響應(yīng)對(duì)象而不使用域?qū)ο蟮膹?qiáng)大工具。

TA貢獻(xiàn)1859條經(jīng)驗(yàn) 獲得超6個(gè)贊
您在請(qǐng)求后不使用構(gòu)造函數(shù) public Question(...) 。你應(yīng)該制定一種方法將選擇與問題聯(lián)系起來
添加回答
舉報(bào)