Cascading Entity Objects with a Foreign Key as Part of a Composite Primary Key

I would like to save an object of my QuestionCompletion class with all the children. One of these children has a composite primary key. And as part of this primary key, I have a foreign key to another object. As a result, I get this error:

 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 

And the last “caused”, of course, is a NullPointerException :

 Caused by: java.lang.NullPointerException 

This is part of my code. The last line causes an error.

 QuestionCompletion questionCompletion = new QuestionCompletion(); List<QuestionCompletionAnswer> answers = new ArrayList<QuestionCompletionAnswer>(); for (;;) { // loop isn't important; it loop for answers ExtendedQuestion extendedQuestion = new ExtendedQuestion(); extendedQuestion.setId(extendedQuestionId); //extendedQuestionId is known to me in that place for (;;) { // loop isn't important; it 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); 

This is my main entity class, which I would like to keep with all its children. I realized that List<QuestionCompletionAnswer> is causing problems. I used cascade = CascadeType.ALL to also save childs elements.

 @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; } 

This is my class - the primary key for the QuestionCompletionAnswer class.

 @Embeddable public class QuestionCompletionAnswerPK implements Serializable { @Column(name = "question_completion_id") protected Long questionCompletionId; @Column(name = "extended_question_id") protected Long extendedQuestionId; } 

And this is the class that uses my EmbeddedId . The questionCompletionId and questionCompletionId attributes are a foreign key for some other objects, so I put below the whole objects of these objects with the @MapsId annotation as @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; } 

Could you tell if my annotations are correct? Perhaps I mixed up several approaches. Or I can’t save my main object with all its children in this case.

EDIT

Now my comparison looks like this:

 @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; } 

The code for the QuestionCompletionAnswerPK class is the same.

 @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; } 

With this mapping, I still get the same exception.

EDIT # 2 However, when I changed the QuestionCompletionAnswer class as follows:

 @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; } 

I get this exception:

 Caused by: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.example.model.domain.QuestionCompletionAnswer 
+4
source share
2 answers

Change 1 and 2 is still not correct. You need to specify the mapid specified in the relation, or you must set the field in the built-in identifier with the value yourself. And when you use mapid, you should not have a join column marked insertable = false or jpa cannot insert a value for you. The last problem that I see is that the new question is not saved, so it does not get the identifier assigned to which the answer can refer - you need to explicitly save the new question in the for loop or mark the connection in the answer to it, the cascade is saved.

+2
source

Why are you mixing jpa and hibernate annotations? jpa annotations alone should be enough. Try with the following mapping (I removed the QuestionCompletionAnswerPK class):

QuestionCompletion.java

 @Entity @Table(name = "question_completion") public class QuestionCompletion { @Id @SequenceGenerator(name = "question_completion_gen", sequenceName = "question_completion_id_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "question_completion_gen") @Column(name = "question_completion_id") private Long id; @OneToMany(cascade = CascadeType.ALL, mappedBy = "questionCompletion") protected List<QuestionCompletionAnswer> answers; } 

QuestionCompletionAnswer.java

 @Entity @Table(name = "extended_question_answer") public class QuestionCompletionAnswer implements Serializable { @Id @ManyToOne @JoinColumn(name = "question_completion_fk") private QuestionCompletion questionCompletion; @Id @ManyToOne @JoinColumn(name = "extended_question_fk") private ExtendedQuestion extendedQuestion; } 

With this mapping, I run the following test case, and it worked:

 QuestionCompletion questionCompletion = new QuestionCompletion(); ExtendedQuestion extendedQuestion = new ExtendedQuestion(); QuestionCompletionAnswer answer = new QuestionCompletionAnswer(); answer.setQuestionCompletion(questionCompletion); answer.setExtendedQuestion(extendedQuestion); questionCompletion.setAnswers(Collections.singletonList(answer)); ... session.save(extendedQuestion); session.save(questionCompletion); 
+1
source

All Articles