Consider the following SQL tables using a Table Per Type inheritance pattern:
CREATE TABLE person (
name VARCHAR(50),
address VARCHAR(50),
is_faculty BOOLEAN,
age SMALLINT NOT NULL,
PRIMARY KEY(name, address, is_faculty)
);
CREATE TABLE student (
name VARCHAR(50),
address VARCHAR(50),
current_grade SMALLINT,
PRIMARY KEY(name, address)
);
CREATE TABLE faculty (
name VARCHAR(50),
address VARCHAR(50),
department VARCHAR(2)
PRIMARY KEY(name, address)
);
Obviously the idea here is that if, for example, I wanted to get a faculty member, I'd use the following join formula:
SELECT *
FROM person
INNER JOIN faculty
ON person.name = faculty.name
AND person.address = faculty.address
AND person.is_faculty = true;
Now consider the following Hibernate entities representing said tables:
import javax.persistence.*;
@Entity
@Table(name = "person")
@IdClass(PersonId.class)
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
@Column(name = "name", length = 50)
private String name;
@Id
@Column(name = "address", length = 50)
private String address;
@Id
@Column(name = "is_faculty")
private boolean isFaculty;
@Column(name = "age", nullable = false)
private int age;
// Constructors, getters, setters, etc.
}
import java.io.Serializable;
import java.util.Objects;
public class PersonId implements Serializable {
private String name;
private String address;
private boolean isFaculty;
// Constructors, getters, setters, hashCode, equals, etc.
}
import javax.persistence.*;
@Entity
@Table(name = "student")
@PrimaryKeyJoinColumns({
@PrimaryKeyJoinColumn(name = "name", referencedColumnName = "name"),
@PrimaryKeyJoinColumn(name = "address", referencedColumnName = "address"),
@PrimaryKeyJoinColumn(name = "is_faculty", referencedColumnName = "is_faculty"),
})
public class Student extends Person {
@Column(name = "current_grade")
private int currentGrade;
// Constructors, getters, setters, etc.
}
import javax.persistence.*;
@Entity
@Table(name = "faculty")
@PrimaryKeyJoinColumns({
@PrimaryKeyJoinColumn(name = "name", referencedColumnName = "name"),
@PrimaryKeyJoinColumn(name = "address", referencedColumnName = "address"),
@PrimaryKeyJoinColumn(name = "is_faculty", referencedColumnName = "is_faculty"),
})
public class Faculty extends Person {
@Column(name = "department", length = 2)
private String department;
// Constructors, getters, setters, etc.
}
There's a clear problem here however; the faculty
and student
tables have no is_faculty
column. But we still need to join on either true
or false
for is_faculty
, as shown in the SELECT statement above.
Normally, this would be solved by using @JoinColumnsOrFormulas
/ @JoinColumnOrFormula
with @JoinFormula
and @JoinColumn
if this weren't an inheritance based join. However, to my knowledge no such alternative exists, such as @PrimaryKeyJoinColumnsOrFormulas
.
My workaround so far has been to just add an is_faculty
column to the faculty
and student
tables, so that both tables share the exact same composite PK columns (letting Hibernate join them using PersonId
).