在JPA中将单个表映射到可嵌入集合

我有一个相当独特的情况,试图将单个表映射到JPA中的多个实体。 我已经阅读了@Embeddable和@ElementCollection,但我不确定如何在我的情况下使用它们(或者如果可以的话)。 一个数据库表包含课程信息。 表格中可以有行,除了一些值(例如房间号和日期)之外,课程中的所有内容都相同。 例如:

TERM_CODE SUBJECT_CODE ROOM DAY INSTRUCTOR_ID 201220 EGRE 0101 TR 123 201220 EGRE 0103 W 124 

有没有办法可以从上面的两行中提取数据,并将公共数据放在一个对象中,将不同的值放在单独对象的集合中? 这是我希望如何定义类的示例:

 @Entity public class Course implements Serializable { @Id @Column(name = "TERM_CODE") private Long termCode; @Column(name = "SUBJECT_CODE") private String subjectCode; @Embedded Collection schedule; public Long getTermCode() { return termCode; } public void setTermCode(Long termCode) { this.termCode = termCode; } public String getSubjectCode() { return subjectCode; } public void setSubjectCode(String subjectCode) { this.subjectCode = subjectCode; } } 

CourseSchedule:

 @Embeddable public class CourseSchedule { private String room; private String day; public String getRoom() { return room; } public void setRoom(String room) { this.room = room; } public String getDay() { return day; } public void setDay(String day) { this.day = day; } public String getInstructorId() { return instructorId; } public void setInstructorId(String instructorId) { this.instructorId = instructorId; } } 

我也很困惑,一旦我将它们映射到我的JPQL在这种情况下会是什么样子。

编辑:

如果我将@Id添加到TERM_CODE列,则返回一个没有Hibernate错误的Course对象,但属于Course的CourseSchedule Collection为null。

编辑2:

我试图将Course和CourseSchedule视为两个独立的表(即使它们不是),但我似乎无法使用@OneToMany和@ManyToOne来加入它们。

 @Entity @IdClass(CourseId.class) @Table(name = "course_table") public class Course implements Serializable { @OneToMany(mappedBy = "course") private Collection schedule; @Id @Column(name = "TERM_CODE") private Long termCode; @Id @Column(name = "SUBJECT_CODE") private Long subjectCode; ... } @Entity @IdClass(CourseScheduleId.class) @Table(name = "course_table") public class CourseSchedule implements Serializable { @ManyToOne @JoinColumns({ @JoinColumn(name="TERM_CODE", referencedColumnName="TERM_CODE"), @JoinColumn(name = "SUBJECT_CODE", referencedColumnName="SUBJECT_CODE") }) private Course course; @Column(name = "TERM_CODE") private Long termCode; @Column(name = "SUBJECT_CODE") private Long subjectCode; @Id private String room; @Id private String day; @Id @Column(name = "INSTRUCTOR_ID") private String instructorId; ... } 

CourseIdCourseScheduleId是用于复合ID的简单类。)上面的映射返回以下错误:

 org.hibernate.MappingException: Foreign key (FK82D03688F590EF27:course_table [TERM_CODE,SUBJECT_CODE])) must have same number of columns as the referenced primary key (course_table [ROOM,DAY,INSTRUCTOR_ID) 

如果有助于使课程更容易,我不需要将CourseSchedule引回课程。

有任何想法吗? 我唯一的另一个想法是将它们定义为完全独立的实体(未加入),然后以某种方式使用JPQL将它们映射到一起。

我一直在尝试一些东西,最接近你想要的是这个(检查CourseSchedule类中的setter setCourse ):

课程

 @Embeddable public class Course implements Serializable { @Column(name = "TERM_CODE") private Long termCode; @Column(name = "SUBJECT_CODE") private String subjectCode; @Transient Collection schedule = new ArrayList(); public void setSchedule(Collection schedule) { this.schedule = schedule; } public Collection getSchedule() { return schedule; } public Long getTermCode() { return termCode; } public void setTermCode(Long termCode) { this.termCode = termCode; } public String getSubjectCode() { return subjectCode; } public void setSubjectCode(String subjectCode) { this.subjectCode = subjectCode; } } 

CourseSchedule

 @Entity(name="Course") public class CourseSchedule { private String room; private String day; @Id @GeneratedValue private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } @Embedded private Course course; public Course getCourse() { return course; } public void setCourse(Course course) { course.schedule.add(this); this.course = course; } public String getRoom() { return room; } public void setRoom(String room) { this.room = room; } public String getDay() { return day; } public void setDay(String day) { this.day = day; } } 

生成数据库表

 id subject_code term_code day room 1 "EGRE" 201220 "TR" "0101" 2 "EGRE" 201220 "W" "0103" 

基本上是另一种方式。 它并不完全符合您的期望,但它可能会激励您获得更好的解决方案,如果您有更多想法或发现有趣的事情,请让我更新…

这就是我提出的(除非有人想出更好的主意):

将Course和CourseSchedule映射到同一个表,但不要加入它们:

 @Entity @IdClass(CourseId.class) @Table(name = "course_table") public class Course implements Serializable { @Transient private Collection schedule; @Id @Column(name = "TERM_CODE") private Long termCode; @Id @Column(name = "SUBJECT_CODE") private Long subjectCode; ... } @Entity @IdClass(CourseScheduleId.class) @Table(name = "course_table") public class CourseSchedule implements Serializable { @Column(name = "TERM_CODE") private Long termCode; @Column(name = "SUBJECT_CODE") private Long subjectCode; @Id private String room; @Id private String day; @Id @Column(name = "INSTRUCTOR_ID") private String instructorId; ... } 

在DAO对象中,分别查询Course和CourseSchedule并将CourseSchedule集合添加到课程:

 public Collection getCourses() { String jpql = "SELECT DISTINCT course FROM Course course"; TypedQuery typedQuery = entityManager .createQuery(jpql, Course.class); // get the Courses and set their schedules Collection courses = typedQuery.getResultList(); setCourseSchedules(courses); return courses; } private void setCourseSchedules(Collection courses) { // query for getting CourseSchedules String jpql = "SELECT DISTINCT schedule FROM CourseSchedule schedule " + "WHERE schedule.subjectCode = :subjectCode " + "AND schedule.termCode = :termCode"; for (Course c : courses) { TypedQuery typedQuery = entityManager .createQuery(jpql, CourseSchedule.class) .setParameter("subjectCode", c.getSubjectCode()) .setParameter("termCode", c.getTermCode()); c.setSchedule(typedQuery.getResultList()); } }