Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cascading save Entity objects with Foreign Key as a part of composite Primary Key

I would like to persist object of my QuestionCompletion class with all child elements. One of these childs has a composite primary key. And as a part of this primary key I have also foreign key to another entity. As a result I am getting 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 by" is of course NullPointerException:

Caused by: java.lang.NullPointerException

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

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);

This is my basic entity class I would like to persist with all its childs elements. I have realized that List<QuestionCompletionAnswer> causes problems. I have used cascade = CascadeType.ALL to allow to persist childs elements also.

@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 - 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 class which uses my EmbeddedId. Attribues questionCompletionId and questionCompletionId are the foreign key for some another entities so I have placed below also whole objects of these entities with @MapsId annotation.

@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 me if my annotations are correct? Maybe I have mixed up few approaches. Or I can't in that case persist my basic object with all of its child elements.

EDIT

Now my mapping looks like:

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

Code of 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 that mapping I am still getting the same exception.

EDIT #2 However when I have changed QuestionCompletionAnswer class in this way:

@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 am getting that exception:

Caused by: org.hibernate.id.IdentifierGenerationException: null id generated 
for:class com.example.model.domain.QuestionCompletionAnswer
like image 330
woyaru Avatar asked Oct 05 '22 19:10

woyaru


1 Answers

Edit 1 and 2 are still not right. You need mapsid specified on the relationship or you must set the field in the embedded id with a value yourself. And when you use mapsid, you shouldn't have the join column marked insertable=false or jpa can't insert a value for you. The last problem I see is that the new question is not persisted so it doesn't get an id assigned that the answer can reference - you need to explicitly persist the new question in the for loop or mark the relationship in the answer to it to cascade persist.

like image 82
Chris Avatar answered Oct 13 '22 12:10

Chris