2012-02-16 74 views
5

我有一個相當獨特的情況,試圖將單個表映射到JPA中的多個實體。我已閱讀@Embeddable和@ElementCollection,但我不知道如何在我的情況下使用它們(或者如果可以的話)。一個數據庫表包含課程信息。表中可以有行,除了少數值之外,課程中的所有內容都是相同的,例如房間號和日期。例如:將單表映射到JPA中的嵌入式集合

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列,則返回休眠無差錯的課程目標,但CourseSchedule的集合,是課程的一部分爲空。

編輯2:

我試圖玩弄處理場和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; 

    ... 

} 

(該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將它們映射到一起。

+0

我想這是一個現有的數據庫?所以你不能在CourseSchedule表中使用TERM_CODE的外鍵?我可能有一個很好的理由來做到這一點,但你只是複製一些數據來存儲ROOM和DAY信息。當你像這樣映射時,hibernate會報告什麼? – bvanvelsen 2012-02-16 20:42:52

+0

不幸的是我無法更改數據庫,並且它都在一張表中。我希望我能說服他們規範化,但這並沒有發生。 – acvcu 2012-02-16 20:48:57

+0

如果我以當前的形式運行它,我會收到錯誤「No identifier specified for entity:Course」,這幾乎是我應該預料到的。另一個問題是數據庫表沒有定義主鍵。 – acvcu 2012-02-16 20:58:10

回答

3

我一直在嘗試一些事情,我也得到你想要的最接近的就是這個(檢查二傳手setCourseCourseSchedule類):

@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

這不是一個壞主意,我會去看看。唯一的問題是,你有它的方式,我不會生成另一個數據庫表?我可能擁有對數據庫的讀/寫訪問權限,但我不擁有這些數據,並且無法在服務器上創建任何新內容。它也不允許我將CourseSchedule作爲課程集合使用,從客戶端角度使用對象時更具邏輯意義。 – acvcu 2012-02-17 13:56:36

+0

我回去試了一下,沒有生成的ID,但我無法得到我的任何查詢來返回沒有空CourseSchedule集合的課程。我沒有使用生成的ID,而是在CourseSchedule上使用了一個複合ID。 – acvcu 2012-02-17 17:01:07

0

這是我想出了(除非有人想出了一個更好的主意):

地圖的課程和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()); 
    } 
}