Java Hibernate/JPA如何修复从子类错误生成的数据库表

Java Hibernate/JPA如何修复从子类错误生成的数据库表,java,hibernate,jpa,Java,Hibernate,Jpa,我在通过JPA和Hibernate注释在数据库中生成表时遇到了一些困难 当执行下面的代码时,它生成具有以下EER图的表 这不是我希望它生成表的方式。 首先,表之间的关系是错误的,它们必须是一对一而不是一对一。 第二,我不想让电子邮件成为学生和老师的主键 在学生中,ovNumber应为主键,在教师中,ovNumber应为employeeNumber 我曾尝试使用@Id注释执行此操作,但出现以下错误: org.hibernate.mapping.JoinedSubclass不能强制转换为org.h

我在通过JPA和Hibernate注释在数据库中生成表时遇到了一些困难

当执行下面的代码时,它生成具有以下EER图的表

这不是我希望它生成表的方式。 首先,表之间的关系是错误的,它们必须是一对一而不是一对一。 第二,我不想让电子邮件成为学生和老师的主键

在学生中,ovNumber应为主键,在教师中,ovNumber应为employeeNumber 我曾尝试使用
@Id
注释执行此操作,但出现以下错误:

org.hibernate.mapping.JoinedSubclass不能强制转换为org.hibernate.mapping.RootClass

当我尝试使用
@MappedSuperClass
时,即使使用
@heritance(strategy=heritancetype.table\u PER\u CLASS)
时,表person也不会生成

现在我的问题是,

如何使子类中的另一个变量成为腐蚀表的主键,同时将超类主键保留为外键

如何将表之间的关系固定为一对一关系而不是一对一关系

下面是一个EER图,它应该是怎样的

下面是用于生成表的模型类

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());
}
}
@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 + "]";
}
}
@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() + "]";
}
}
Student.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());
}
}
@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 + "]";
}
}
@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() + "]";
}
}

在老师和学生身上试试这个

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

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

您的目标是实现继承,其中
Person
是您的超类
Teacher
Student
是其中的子类。JPA中的继承与sql实现不同。我建议你读一下我刚才写的东西。也读

###编辑##

以下是针对您所要求的每个实体的不同主键的解决方案,但我认为这是一种不同寻常的设计(对于其他实体,请参考原始消息):

人:

@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实体。将人声明为抽象实体,将教师和学生逐个扩展

示例代码:

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

这似乎不起作用,我知道如果不扩展Person类,这是一种方法。然而,老师和学生都扩展了Person类。谢谢你的回答,这似乎并没有做我想要的正确的事情。表之间的关系仍然是一对一而不是一对一。此外,我希望避免使用id,因为在这种情况下,电子邮件始终是唯一的值。这也不包括为学生和教师设置不同主键的部分。如果您能编辑您的答案以解决这些问题,我将不胜感激。在它的SQL实现中,它们似乎是一对一(一个人可以是多个学生),但JPA提供商将对它们进行独特处理,因为它知道这是继承。在对象关系中,除了老师或学生,你永远不会拯救一个人。由于有不同的主键,我根据您的需要更新了我的答案,尽管您的模型有些混乱。我认为使用不同的PK没有任何好处,因为它们是相互关联的。感谢您的时间,我得出结论,我所需的积分组合是不可能的。我已经放弃了使用不同的主键,现在它正确地生成了数据库。然而,这并不能完全解决我的问题,我仍然会投票支持你的答案,因为它部分解决了我的问题。