Reputation: 1086
I'm experiencing some difficulties with generating tables in the database through JPA and Hibernate annotations.
When the below code is executed it generates the tables with the following EER diagram.
This is not how I want it to generate the tables. First of all the relations between the tables are wrong, they need to be OneToOne and not OneToMany. Secondly, i don't want email to be the primary key in student and teacher.
In Student the ovNumber should be primary key and in Teacher the employeeNumber
I have tried doing it with the @Id
annotation but that gives me the following error:
org.hibernate.mapping.JoinedSubclass cannot be cast to org.hibernate.mapping.RootClass
When i try to use @MappedSuperClass
the table person does not generate, even when using @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
.
Now my question,
How do I make another variable in subclasses the primary key for the corrosponding table whilst keeping the superclass primary key as foreign key?
How do I fix the relationship between the tables to be an OneToOne relation rather than a OneToMany relation?
Here is an EER diagram of how it should be.
Below are the model classes that are used to generate the tables.
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() + "]";
}
}
Upvotes: 2
Views: 923
Reputation: 628
Your goal is to implement inheritance, where Person
is your superclass. Teacher
and Student
are subclasses of that. Inheritance in JPA is not like it's sql-implementation. I advice to read following answer I wrote a while ago. Also read JavaEE 7 - Entity Inheritance Tutorial.
##EDIT##
Here is the solution with different primary keys for each entity for what u asked, still I think that is unusual design (for others please refer to original message):
Person:
@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
}
Teacher
@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
}
Student
@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
}
##Original Message##
For your problem I suggest to remodel your jpa-entities. Declare Person as an abstract Entity, extend Teacher and Student by Person.
examplecode:
Person
@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
}
Teacher and Student respectively
@Entity
public class Teacher extends Person {
//no ID needed, it inherits the id of Person
}
Upvotes: 3
Reputation: 2413
try this in Teacher and Student
@OneToOne
@PrimaryKeyJoinColumn(name="person_email", referencedColumnName="email")
private Person preson;
instead of :
@PrimaryKeyJoinColumn(name="email", referencedColumnName="email")
Upvotes: 0