2017-04-04 33 views
2

我在通過JPA和Hibernate註釋在數據庫中生成表時遇到了一些困難。Hibernate/JPA如何修復從子類中生成數據庫表的錯誤

當執行下面的代碼時,它將生成具有以下EER圖表的表格。

Generated EER Diagram of Person, Student and Teacher

這不是我多麼希望它來生成表。 首先,表格之間的關係是錯誤的,它們需要是OneToOne而不是OneToMany。其次,我不希望電子郵件成爲學生和老師的主要關鍵。

學生的ovNumber應該是主鍵和教師的employeeNumber 我曾嘗試與@Id註釋這樣做,但使我有以下錯誤:

org.hibernate.mapping.JoinedSubclass cannot be cast to org.hibernate.mapping.RootClass

當我嘗試使用@MappedSuperClass表即使使用@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS),人也不會生成。

現在我的問題,

我如何在子類中的另一個變量的corrosponding表的主鍵,同時保持超主鍵外鍵?

如何解決表之間的關係是OneToOne關係而不是OneToMany關係?

下面是它應該如何的EER圖。

EER Diagram of Person, Student and Teacher the way it should be

下面是用於生成的表的模型類。

Person.java

@Entity 
@Polymorphism(type=PolymorphismType.IMPLICIT) 
@Inheritance(strategy=InheritanceType.JOINED) 
public class Person implements Comparable<Person>, Serializable { 

private static final long serialVersionUID = 1L; 

@Id 
@Column(name="email", length=64, nullable=false) 
private String email; 

@Column(name="firstName", length=255) 
private String firstName; 

@Column(name="insertion", length=255) 
private String insertion; 

@Column(name="lastName", length=255) 
private String lastName; 

public Person() {} 

/** 
* constructor with only email. 
* 
* @param email 
*/ 
public Person(String email) { 
    this.email = email; 
} 

/** 
* @param email 
* @param firstName 
* @param insertion 
* @param lastName 
*/ 
public Person(String email, String firstName, String insertion, String lastName){ 
    this.setEmail(email); 
    this.setFirstName(firstName); 
    this.setInsertion(insertion); 
    this.setLastName(lastName); 
} 

//getters and setters 
public String getEmail() { 
    return email; 
} 

public void setEmail(String email) { 
    this.email = email; 
} 

public String getFirstName() { 
    return firstName; 
} 

public void setFirstName(String firstName) { 
    this.firstName = firstName; 
} 

public String getInsertion() { 
    return insertion; 
} 

public void setInsertion(String insertion) { 
    this.insertion = insertion; 
} 

public String getLastName() { 
    return lastName; 
} 

public void setLastName(String lastName) { 
    this.lastName = lastName; 
} 

@Override 
public int compareTo(Person o) { 
    return email.compareTo(o.getEmail()); 
} 
} 

Teacher.java

@Entity 
@Table(name="teacher") 
@PrimaryKeyJoinColumn(name="email", referencedColumnName="email") 
public class Teacher extends Person { 

private static final long serialVersionUID = 1L; 

//this needs to be the pk of teacher table 
//@Id 
@Column(name="employeeNumber", length=6, nullable=false) 
private int employeeNumber; 

@Column(name="abbreviation", length=6) 
private String abbreviation; 

public Teacher(){} 

/** 
* @param employeeNumber 
* @param email 
* @param firstName 
* @param insertion 
* @param lastName 
*/ 
public Teacher(int employeeNumber, String email, String firstName, String insertion, String lastName){ 
    super(email, firstName, insertion, lastName); 
    this.employeeNumber = employeeNumber; 
    setAbbreviation(); 
} 

public String getAbbreviation() { 
    return abbreviation; 
} 

public void setAbbreviation() { 
    this.abbreviation = getLastName().substring(0, 4).toUpperCase() + getFirstName().substring(0, 2).toUpperCase(); 
} 

public void setAbbreviation(String abbreviation){ 
    this.abbreviation = abbreviation; 
} 

public int getEmployeeNumber() { 
    return employeeNumber; 
} 

public void setEmployeeNumber(int employeeNumber) { 
    this.employeeNumber = employeeNumber; 
} 

@Override 
public String toString() { 
    return "Teacher [abbreviation=" + abbreviation + ", employeeNumber=" + employeeNumber + "]"; 
} 
} 

Student.java

@Entity 
@Table(name="student") 
@PrimaryKeyJoinColumn(name="email", referencedColumnName="email") 
public class Student extends Person { 

private static final long serialVersionUID = 1L; 

@Column(name="cohort") 
private int cohort; 

//FIXME this needs to be the pk of student table 
//@Id 
@Column(name="ovNumber", nullable=false) 
private int studentOV; 


public Student(){} 

public Student(int studentOV, int cohort, String email, String firstName, 
     String insertion, String lastName) { 
    super(email, firstName, insertion, lastName); 
    this.studentOV = studentOV; 
    this.cohort = cohort; 
} 

public int getCohort() { 
    return cohort; 
} 

public void setCohort(int cohort) { 
    this.cohort = cohort; 
} 

public int getStudentOV() { 
    return studentOV; 
} 

public void setStudentOV(int studentOV) { 
    this.studentOV = studentOV; 
} 

@Override 
public int compareTo(Person o) { 
    return getEmail().compareTo(o.getEmail()); 
} 

@Override 
public String toString() { 
    return "Student [firstName=" + getFirstName() + ", insertion=" + getInsertion() + ", lastName=" + getLastName() + ", email=" 
      + getEmail() + ", cohort=" + getCohort() + ", studentOV=" + getStudentOV() + "]"; 
} 
} 

回答

0

嘗試這老師和學生

@OneToOne 
@PrimaryKeyJoinColumn(name="person_email", referencedColumnName="email") 
private Person preson; 

代替:

@PrimaryKeyJoinColumn(name="email", referencedColumnName="email") 
+1

學生這似乎並沒有工作,我知道這是做它,如果你不延長路Person類。然而老師和學生班都擴展了Person類。 –

3

你的目標是實現繼承,其中Person是你的超類。 TeacherStudent是那個的子類。 JPA中的繼承不像它的sql實現。我建議閱讀following answer我剛纔寫的。另請閱讀JavaEE 7 - Entity Inheritance Tutorial

## EDIT ##

這裏是爲每個實體什麼ü問不同的主鍵的解決方案,我仍然認爲,這是不同尋常的設計(替他人請參見原始消息):

人:

@Entity 
public class Person implements Serializable { 
    @Id 
    @Column 
    private String email; 

    @OneToOne(mappedBy = "person") 
    private Teacher teacher; 

    @OneToOne(mappedBy = "person") 
    private Student student; 
    //more fields 
} 

教師

@Entity 
public class Teacher implements Serializable { 
    @Id 
    @Column 
    private Integer employeeNumber; 

    //constrained to have to be assigned to a Person 
    //remove constraints if not needed 
    @OneToOne(optional = false) 
    @JoinColumn(unique = true, nullable = false) 
    private Person person; 

    //more fields 
} 

學生

@Entity 
public class Student implements Serializable { 
    @Id 
    @Column 
    private Integer ovNumber; 

    //constrained to have to be assigned to a Person 
    //remove constraints if not needed 
    @OneToOne(optional = false) 
    @JoinColumn(unique = true, nullable = false) 
    private Person person; 

    //more fields 
} 

##原始消息##

對於你的問題,我建議改裝你的JPA實體。將Person聲明爲抽象實體,逐個擴展Teacher和Student。

examplecode:

@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name = "PERSON_TYPE") 
public abstract class Person implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column 
    private Integer id; 

    //add your needed fields 
} 

教師分別

@Entity 
public class Teacher extends Person { 
    //no ID needed, it inherits the id of Person 
} 
+0

謝謝你的回答,這似乎並沒有做我想要的正確的事情。表格之間的關係仍然是OneToMany而不是OneToOne。此外,我想避免使用ID作爲電子郵件在這種情況下總是一個獨特的價值。這也不包括爲學生和教師設置不同主鍵的部分。如果你能編輯你的答案來解決這些問題,我將不勝感激。 –

+0

在它的SQL實現中,它似乎是OneToMany(一個人可以是多個學生),但是JPA提供程序會將它們視爲唯一的,因爲它知道它是繼承。在對象關係中,你永遠不會保存一個人,而是一個教師或學生。爲了擁有不同的主鍵,我更新了我的答案以滿足您的需求,儘管您的模型有點令人困惑。我看到使用不同的PK沒有任何好處,因爲它們連接在一起。 –

+0

感謝您的時間,我得出的結論是,我所需的積分的組合是不可能的。我放棄了不同的主鍵,現在它正確地生成數據庫。然而,這並不能完全解決我的問題,我仍然會提高你的答案,部分解決我的問題。 –