将外键作为复合主键的一部分进行级联保存实体对象

woy*_*aru 5 java spring hibernate jpa spring-mvc

我想QuestionCompletion使用所有子元素坚持我班的对象。这些孩子之一具有复合主键。作为该主键的一部分,我还具有另一个实体的外键。结果,我得到这个错误:

Exception caught during request processing: javax.ejb.EJBTransactionRolledbackException:
could not set a field value by reflection setter of com.example.model.domain.QuestionCompletionAnswerPK.questionCompletionId
javax.ejb.EJBTransactionRolledbackException: could not set a field value by reflection
setter of com.example.model.domain.QuestionCompletionAnswerPK.questionCompletionId
Run Code Online (Sandbox Code Playgroud)

最后一个“由...引起”当然是NullPointerException

Caused by: java.lang.NullPointerException
Run Code Online (Sandbox Code Playgroud)

这是我的代码的一部分。最后一行导致错误。

QuestionCompletion questionCompletion = new QuestionCompletion();
List<QuestionCompletionAnswer> answers = new ArrayList<QuestionCompletionAnswer>();
for (;;) { // loop isn't important; it's loop for answers
    ExtendedQuestion extendedQuestion = new ExtendedQuestion();
    extendedQuestion.setId(extendedQuestionId); //extendedQuestionId is known to me in that place
    for (;;) { // loop isn't important; it's loop for question answers
        //questionCompletion and extendedQuestion are popualted here
        QuestionCompletionAnswer questionCompletionAnswer = new QuestionCompletionAnswer();
        questionCompletionAnswer.setQuestionCompletion(questionCompletion); 
        questionCompletionAnswer.setExtendedQuestion(extendedQuestion); 
        answers.add(questionCompletionAnswer);
    }
}
questionCompletion.setAnswers(answers);
questionCompletionService.saveOrMerge(questionCompletion);
Run Code Online (Sandbox Code Playgroud)

这是我想要保留其所有childs元素的基本实体类。我已经意识到这List<QuestionCompletionAnswer>会引起问题。我曾经cascade = CascadeType.ALL也允许保留childs元素。

@javax.persistence.Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "question_completion")
public class QuestionCompletion implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "question_completion_gen")
    @SequenceGenerator(name = "question_completion_gen", sequenceName = "question_completion_id_seq")
    @Column(name = "question_completion_id")
    private Long id;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "extended_question_id")
    protected List<QuestionCompletionAnswer> answers;
}
Run Code Online (Sandbox Code Playgroud)

这是我的课程-该QuestionCompletionAnswer课程的主键。

@Embeddable
public class QuestionCompletionAnswerPK implements Serializable {

    @Column(name = "question_completion_id")
    protected Long questionCompletionId;

    @Column(name = "extended_question_id")
    protected Long extendedQuestionId;
}
Run Code Online (Sandbox Code Playgroud)

这是使用my的类EmbeddedId。属性questionCompletionIdquestionCompletionId是其他某些实体的外键,因此,我还在这些实体的整个对象下添加了@MapsId注释。

@javax.persistence.Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "extended_question_answer")
public class QuestionCompletionAnswer implements Serializable {

    @EmbeddedId
    private QuestionCompletionAnswerPK id;

    @ManyToOne
    @MapsId(value = "questionCompletionId")
    @JoinColumn(name = "question_completion_id", nullable = false, insertable = false, updatable = false)
    protected QuestionCompletion questionCompletion;

    @ManyToOne
    @MapsId(value = "extendedQuestionId")
    @JoinColumn(name = "extended_question_id", nullable = false, insertable = false, updatable = false)
    protected ExtendedQuestion extendedQuestion;
}
Run Code Online (Sandbox Code Playgroud)

您能告诉我我的注解是否正确吗?也许我混淆了几种方法。否则,在这种情况下,我无法将基本对象及其所有子元素都保留下来。

编辑

现在我的映射如下:

@javax.persistence.Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "question_completion")
public class QuestionCompletion implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "question_completion_gen")
    @SequenceGenerator(name = "question_completion_gen", sequenceName = "question_completion_id_seq")
    @Column(name = "question_completion_id")
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "questionCompletion")
    protected List<QuestionCompletionAnswer> answers;
}
Run Code Online (Sandbox Code Playgroud)

QuestionCompletionAnswerPK类的代码是相同的。

@javax.persistence.Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "extended_question_answer")
public class QuestionCompletionAnswer implements Serializable {

    @EmbeddedId
    private QuestionCompletionAnswerPK id;

    @ManyToOne(cascade = CascadeType.PERSIST)
    @MapsId(value = "questionCompletionId")
    @JoinColumn(name = "question_completion_id", nullable = false)
    protected QuestionCompletion questionCompletion;

    @ManyToOne
    @MapsId(value = "extendedQuestionId")
    @JoinColumn(name = "extended_question_id", nullable = false)
    protected ExtendedQuestion extendedQuestion;
}
Run Code Online (Sandbox Code Playgroud)

通过该映射,我仍然遇到相同的异常。

编辑#2 但是,当我QuestionCompletionAnswer以这种方式更改课程时:

@javax.persistence.Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "extended_question_answer")
public class QuestionCompletionAnswer implements Serializable {

    @EmbeddedId
    private QuestionCompletionAnswerPK id;

    @ManyToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "question_completion_id", nullable = false, insertable = false, updatable = false)
    protected QuestionCompletion questionCompletion;

    @ManyToOne
    @JoinColumn(name = "extended_question_id", nullable = false, insertable = false, updatable = false)
    protected ExtendedQuestion extendedQuestion;
}
Run Code Online (Sandbox Code Playgroud)

我收到该异常:

Caused by: org.hibernate.id.IdentifierGenerationException: null id generated 
for:class com.example.model.domain.QuestionCompletionAnswer
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 4

编辑1和2仍然不对。您需要在关系上指定mapsid,或者您必须自己设置嵌入id 中的字段。当您使用mapsid时,您不应该将连接列标记为insertable = false,否则jpa无法为您插入值。我看到的最后一个问题是新问题没有持久化,因此它没有分配一个答案可以引用的 id - 您需要在 for 循环中显式地持久化新问题或将其答案中的关系标记为级联持续存在。