2012-02-16 15 views
5

Mam dość wyjątkową sytuację, próbując zmapować pojedynczą tabelę do wielu podmiotów w WZP. Czytałem o @Embeddable i @ElementCollection, ale nie jestem pewien, jak używać ich w mojej sytuacji (lub jeśli mogę). Jedna tabela bazy danych zawiera informacje o kursie. W tabeli mogą znajdować się wiersze, w których wszystko w Kursie jest takie samo, z wyjątkiem kilku wartości, takich jak numer pokoju i dzień. Na przykład:Odwzorowywanie pojedynczego stołu na zbiór do umieszczenia w JPA

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

Czy istnieje sposób, że mogę wyciągnąć dane z dwóch rzędach, jak wyżej, i umieścić wspólnych danych w jednym obiekcie i różne wartości w zbiorze oddzielne obiekty? Oto przykład, jak chciałbym mieć klasy zdefiniowane:

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

Ja również jestem mylić, co mój JPQL będzie wyglądać w tej sytuacji kiedyś je zmapowany.

EDIT:

Jeśli dodać @Id do kolumny TERM_CODE, obiekt jest oczywiście zwrócone bez błędów hibernacji, ale Collection CourseSchedule który jest częścią kursu jest null.

EDIT 2:

Próbowałem się bawić z leczenia Course i CourseSchedule jako dwóch oddzielnych tabelach (choć nie są one), ale nie wydaje się uzyskać je za pomocą @OneToMany i dołączył @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 i CourseScheduleId są proste ćwiczenia stosowane do złożonego ID.) Powyższa mapowanie zwrócić następujący błąd:

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) 

I nie potrzebują CourseSchedule Powracając do oczywiście jeśli to pomaga w ułatwianiu.

Wszelkie pomysły? Moją jedyną myślą jest zdefiniowanie ich jako całkowicie oddzielnych elementów (nie połączonych), a następnie w jakiś sposób zmapować je razem za pomocą JPQL.

+0

Chyba to istniejąca DB? więc nie możesz użyć klucza obcego do TERM_CODE w tabeli CourseSchedule? Mogę mieć dobry powód, aby to zrobić, ale duplikujesz sporo danych tylko po to, aby przechowywać informacje o POKÓJ i DNIU. Co oznacza raport hibernacji, gdy mapujesz go w ten sposób? – bvanvelsen

+0

Niestety nie mogę zmienić bazy danych, a wszystko to w jednej tabeli. Chciałbym przekonać ich, żeby to znormalizowali, ale tak się nie dzieje. – acvcu

+0

Jeśli uruchomię go w obecnym formularzu, pojawia się błąd "Brak identyfikatora dla obiektu: Kurs", którego prawie powinienem się spodziewać. Inną kwestią jest to, że tabela bazy danych nie definiuje klucza podstawowego. – acvcu

Odpowiedz

3

staram pewne rzeczy, a najbliżej mogę dostać się do tego, co chcesz, jest to (sprawdź setter setCourse w klasie CourseSchedule):

Kurs

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

wygenerowana tabela bazy danych

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

Zasadniczo na odwrót. Nie jest to dokładnie to, czego się spodziewasz, ale może Cię zainspirować do lepszego rozwiązania, proszę informuj mnie na bieżąco, jeśli masz więcej pomysłów lub znalazłeś coś interesującego ...

+0

To nie jest zły pomysł, rzucę okiem. Jedynym problemem jest to, że w jaki sposób go masz, czy nie musiałbym generować innej tabeli bazy danych? Prawdopodobnie mam dostęp do odczytu/zapisu do bazy danych, ale nie jestem właścicielem danych i nie mogę utworzyć niczego nowego na serwerze. To także nie pozwala mi mieć CourseSchedule jako zbioru kursów, co ma bardziej logiczny sens w przypadku korzystania z obiektów z perspektywy klienta. – acvcu

+0

Wróciłem i wypróbowałem to bez wygenerowanego identyfikatora, ale nie mogłem uzyskać żadnego z moich zapytań, aby zwrócić Kursy bez zerowych kolekcji CourseSchedule. Zamiast korzystać z wygenerowanego identyfikatora, użyłem złożonego identyfikatora w CourseSchedule. – acvcu

0

To co wymyśliłem (chyba, że ​​ktoś wymyśli lepszego pomysłu):

mapie przebieg i CourseSchedule do tej samej tabeli, ale nie dołączy do nich:

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

    ... 

} 

W obiekt DAO, kwerendy przebiegu i CourseSchedule osobno i dodać do kolekcji CourseSchedule kursu:

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()); 
    } 
} 
Powiązane problemy