简体   繁体   中英

Hibernate joining tables with multiple primary keys

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM