I have figured out how to join 2 tables with single primary key. But now I need to join 4 tables and some of these table with composite primary keys.
Here is my table picture
And I want to join them, so I generate classes for them:
// Record
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "record")
public class Record implements java.io.Serializable{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "student_id")
private Integer studentId;
@Id
@Column(name = "exam_id")
private Integer examId;
@Column(name = "total_score")
private Integer totalScore;
@Column(name = "student_score")
private Integer studentScore;
@Column(name = "submission_id")
private Integer submissionId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "student_id")
private Student student;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "submission_id")
private Submission submission;
}
// Submission
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "submission")
public class Submission implements java.io.Serializable{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "submission_id")
private Integer submissionId;
@Id
@Column(name = "question_id")
private Integer questionId;
@Column(name = "stu_answer")
private String stuAnswer;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "submission")
private Record record;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "submission")
private Set<Question> question;
}
// Question
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "question")
public class Question implements java.io.Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "question_id")
private Integer questionId;
@Column(name = "content")
private String content;
@Column(name = "score")
private Integer score;
@Column(name = "is_delete")
private Integer isDelete;
@Column(name = "option_id")
private Integer optionId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "submission_id")
private Submission submission;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "optional_id")
private Optional optional;
}
// Optional
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "optional")
public class Optional implements java.io.Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "option_id")
private Integer optionId;
@Column(name = "content")
private String content;
@Column(name = "is_delete")
private Integer isDelete;
@Column(name = "answer")
private String answer;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "optional")
private Question question;
}
// Final class to store information
public class RcdSubQuesOpt {
private Integer studentId;
private Integer examId;
private Integer questionId;
private String stuAnswer;
private String qContent;
private String oContent;
private String answer;
}
And this is code for JPA
@Override
public List<RcdSubQuesOpt> getRcdSubQuesOpt(int studentID, int examId) {
Session session = this.getSession();
List<RcdSubQuesOpt> results;
Transaction transaction = null;
try {
transaction = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<RcdSubQuesOpt> criteriaQuery = criteriaBuilder.createQuery(RcdSubQuesOpt.class);
// Try to join tables
Root<Record> pRoot = criteriaQuery.from(Record.class);
pRoot.join("submission", JoinType.INNER);
pRoot.join("question", JoinType.INNER);
pRoot.join("optional", JoinType.INNER);
criteriaQuery.multiselect(
pRoot.get(columns in RcdSubQuesOpt Class......));
// Try to add constraints
Predicate predicate = pRoot.get("examId").in(Arrays.asList(1));
criteriaQuery.where(predicate);
// try to do queries
results = session.createQuery(criteriaQuery).getResultList();
transaction.commit();
} catch (Exception e) {
results = null;
if (transaction != null) {
transaction.rollback();
}
} finally {
session.close();
}
return results;
}
But hibernate throw error as following:
Enitial SessionFactory creation failedA Foreign key refering com.domain.Submission from com.domain.Record has the wrong number of column. should be 2
Exception in thread "main" java.lang.ExceptionInInitializerError
I think it's the composite primary keys problem. But solution I searched is not suitable to solve it. Anyone give me some advice? Thanks!
To reference a composite primary key, you need to use @JoinColumns
(plural).
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "sub_submission_id", referencedColumnName = "submission_id"),
@JoinColumn(name = "sub_question_id", referencedColumnName = "question_id")
})
private Submission submission;
However, I must admit, I don't understand your model - especially why Submission
has a composite PK with question_id
. It looks that one Submission
has many Questions
, why to include question_id
as part of Submission PK?
Perhaps, I'm missing something, because the diagram is not fully visible.