2012-02-16 3 views
5

JPAの単一のテーブルを複数のエンティティにマップしようとするかなり独特の状況があります。 @Embeddableと@ElementCollectionについて読んだことがありますが、自分の状況(または可能であれば)でそれらを使用する方法がわかりません。 1つのデータベーステーブルはコース情報を保持します。テーブルには、部屋番号や日などのいくつかの値を除いて、コース内のすべてが同じ行があります。たとえば:JPAの埋め込み可能なコレクションへの単一テーブルのマッピング

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

は、私は上記のように二列からデータを取得し、別のオブジェクトのコレクションには1つのオブジェクトに共通のデータと異なる値を置くことができる方法はありますか?ここで私はクラスが定義されているしたいのですが方法の例です:

@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はこのような状況でどのように見えるかのように混乱していますマップされます。

編集:私はTERM_CODE列に@Idを追加する場合

は、コースオブジェクトはHibernateのエラーなしで返されますが、コースの一部であるCourseScheduleコレクションがnullです。

EDIT 2:

私は(そうでないならにもかかわらず)は、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

これは既存のDBだと思いますか? CourseScheduleテーブルのTERM_CODEに外部キーを使用することはできません。私はこれを行う良い理由があるかもしれませんが、ちょうどROOMとDAYの情報を保存するためにかなりのデータを複製しています。このようにマップすると、何が休止状態になりますか? – bvanvelsen

+0

残念ながら私はデータベースを変更することはできません。それはすべて1つのテーブルにあります。私は彼らにそれを正常化させることを納得させることができればいいが、それは起こっていない。 – acvcu

+0

私はそれを現在のフォームで実行した場合、「エンティティには識別子が指定されていません:コース」というエラーが表示されます。別の問題は、データベーステーブルがプライマリキーを定義していないことです。 – acvcu

答えて

3

私はいくつかのことをしようとしている、と私はあなたが欲しいものを得る最も近いが、これは(CourseScheduleクラスでセッター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; 
} 
} 

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

+0

私は戻って、このw/outを生成したIDを試しましたが、null CourseScheduleコレクションなしでCourseを返すクエリを取得できませんでした。生成されたIDを使用する代わりに、CourseScheduleでコンポジットIDを使用しました。 – acvcu

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コレクションを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()); 
    } 
} 
関連する問題