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

Java 在JPA中将单个表映射到可嵌入集合,java,hibernate,jpa,Java,Hibernate,Jpa,在JPA中,我有一个非常独特的情况,试图将一个表映射到多个实体。我读过@Embeddeble和@ElementCollection,但我不确定在我的情况下如何使用它们(或者如果可以的话)。one数据库表保存课程信息。表中可以有行,其中课程中的所有内容都是相同的,除了一些值,例如房间号和日期。例如: TERM_CODE SUBJECT_CODE ROOM DAY INSTRUCTOR_ID 201220 EGRE 0101 TR

在JPA中,我有一个非常独特的情况,试图将一个表映射到多个实体。我读过@Embeddeble和@ElementCollection,但我不确定在我的情况下如何使用它们(或者如果可以的话)。one数据库表保存课程信息。表中可以有行,其中课程中的所有内容都是相同的,除了一些值,例如房间号和日期。例如:

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;
    }
}
我也很困惑,在这种情况下,一旦映射到JPQL,我的JPQL会是什么样子

编辑:

如果我将@Id添加到TERM_CODE列,则返回的课程对象没有Hibernate错误,但作为课程一部分的CourseSchedule集合为null

编辑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;

    ...

}
如果这有助于简化课程,我不需要课程安排,也不需要返回课程


有什么想法吗?我唯一的另一个想法是将它们定义为完全独立的实体(未连接),然后使用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<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;
 }
}
生成的数据库表

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

基本上相反。这并不完全是您所期望的,但它可能会激励您寻找更好的解决方案,如果您有更多想法或发现有趣的内容,请随时向我通报。

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

将课程和课程时间表映射到同一个表,但不要将其加入:

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

    ...

}
@实体
@IdClass(CourseId.class)
@表(name=“课程表”)
公共类课程实现可序列化{
@短暂的
私人收集时间表;
@身份证
@列(name=“TERM\u CODE”)
私人长期守则;
@身份证
@列(name=“主题代码”)
专用长主题代码;
...
}
@实体
@IdClass(CourseScheduleId.class)
@表(name=“课程表”)
公共类CourseSchedule实现可序列化{
@列(name=“TERM\u CODE”)
私人长期守则;
@列(name=“主题代码”)
专用长主题代码;
@身份证
私人弦乐室;
@身份证
私人弦日;
@身份证
@列(name=“讲师ID”)
私有字符串指令ID;
...
}
在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());
    }
}
getCourses()公共集合{
String jpql=“从课程中选择不同的课程”;
TypedQuery TypedQuery=entityManager
.createQuery(jpql,Course.class);
//获取课程并设置他们的时间表
Collection courses=typedQuery.getResultList();
设置课程时间表(课程);
返回课程;
}
私人课程时间表(收集课程){
//查询获取课程时间表
String jpql=“从课程时间表中选择不同的时间表”
+“其中schedule.subjectCode=:subjectCode”
+“和schedule.termCode=:termCode”;
(课程c:课程){
TypedQuery TypedQuery=entityManager
.createQuery(jpql,CourseSchedule.class)
.setParameter(“subjectCode”,c.getSubjectCode())
.setParameter(“termCode”,c.getTermCode());
c、 setSchedule(typedQuery.getResultList());
}
}

我想这是一个现有的数据库?那么您不能在CourseSchedule表中使用术语_代码的外键?我可能有很好的理由这样做,但您复制了相当多的数据,只是为了存储房间和日常信息。当您这样映射它时,hibernate会报告什么?不幸的是,我无法更改数据库,而且它都在一个表中。我希望我能说服他们对其进行规范化,但这并没有发生。如果我以当前的形式运行它,我会得到错误“没有为实体指定标识符:课程”,这几乎是我应该预料到的。另一个问题是数据库表没有定义主键。这不是个坏主意,我来看看。唯一的问题是,按照您的方式,我不需要生成另一个数据库表吗?我可能具有对数据库的读/写访问权限,但我不拥有数据,也无法在服务器上创建任何新内容。它也不允许我将CourseSchedule作为课程集合,这在从客户端角度使用对象时更具逻辑意义。我返回并尝试了这个方法,并删除了生成的ID,但我无法让任何查询返回没有空CourseSchedule集合的课程。我没有使用生成的ID,而是在CourseSchedule上使用了复合ID。
id    subject_code    term_code    day    room
1      "EGRE"           201220     "TR"   "0101"
2      "EGRE"           201220     "W"    "0103"
@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;

    ...

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