我有一个相当独特的情况,试图将单个表映射到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<CourseSchedule> 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对象,但属于该课程的CourseSchedule Collection为空。
编辑2:
我试图将Course和CourseSchedule视为两个独立的表(即使它们不是),但我似乎无法使用@OneToMany和@ManyToOne来加入它们。
@Entity
@IdClass(CourseId.class)
@Table(name = "course_table")
public class Course implements Serializable {
@OneToMany(mappedBy = "course")
private Collection<CourseSchedule> 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;
...
}
(CourseId
和CourseScheduleId
是用于复合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将它们映射在一起。
答案 0 :(得分:3)
我一直在尝试一些事情,而我最接近你想要的是这个(检查setCourse
类中的setter CourseSchedule
):
场
@Embeddable
public class Course implements Serializable {
@Column(name = "TERM_CODE")
private Long termCode;
@Column(name = "SUBJECT_CODE")
private String subjectCode;
@Transient
Collection<CourseSchedule> schedule = new ArrayList<CourseSchedule>();
public void setSchedule(Collection<CourseSchedule> schedule) {
this.schedule = schedule;
}
public Collection<CourseSchedule> 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"
基本上是相反的方式。它并不完全符合您的期望,但它可能会激励您获得更好的解决方案,如果您有更多想法或发现有趣的东西,请随时更新......
答案 1 :(得分:0)
这就是我提出的(除非有人想出更好的主意):
将Course和CourseSchedule映射到同一个表,但不要加入它们:
@Entity
@IdClass(CourseId.class)
@Table(name = "course_table")
public class Course implements Serializable {
@Transient
private Collection<CourseSchedule> 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<Course> getCourses() {
String jpql = "SELECT DISTINCT course FROM Course course";
TypedQuery<Course> typedQuery = entityManager
.createQuery(jpql, Course.class);
// get the Courses and set their schedules
Collection<Course> courses = typedQuery.getResultList();
setCourseSchedules(courses);
return courses;
}
private void setCourseSchedules(Collection<Course> 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<CourseSchedule> typedQuery = entityManager
.createQuery(jpql, CourseSchedule.class)
.setParameter("subjectCode", c.getSubjectCode())
.setParameter("termCode", c.getTermCode());
c.setSchedule(typedQuery.getResultList());
}
}