Отображение одной таблицы в встраиваемую коллекцию в JPA - PullRequest
5 голосов
/ 17 февраля 2012

У меня довольно уникальная ситуация, когда я пытаюсь сопоставить одну таблицу нескольким объектам в 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 в этой ситуации, когда я сопоставлю их.

EDIT:

Если я добавлю @Id в столбец TERM_CODE, объект курса будет возвращен без ошибок Hibernate, но коллекция CourseSchedule, являющаяся частью курса, будет нулевой.

РЕДАКТИРОВАТЬ 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 - простые классы, используемые для составного идентификатора.) Приведенное выше отображение возвращает следующую ошибку:

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.

Ответы [ 2 ]

3 голосов
/ 17 февраля 2012

Я пробовал некоторые вещи, и ближе всего я получаю то, что вы хотите, это (проверьте сеттер setCourse в классе 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"

В основном наоборот. Это не совсем то, что вы ожидаете, но это может вдохновить вас на лучшее решение, пожалуйста, держите меня в курсе, если у вас есть идеи или нашли что-то интересное ...

0 голосов
/ 17 февраля 2012

Вот то, что я придумал (если кто-то не придумал более удачную идею):

Сопоставьте 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 в Course:

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());
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...