2017-04-04 61 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

感谢您的时间,我得出的结论是,我所需的积分的组合是不可能的。我放弃了不同的主键,现在它正确地生成数据库。然而,这并不能完全解决我的问题,我仍然会提高你的答案,部分解决我的问题。 –