У меня проблема с моделированием/пониманием частичного, нераздельного наследования с аннотациями JPA.
Вот четыре таблицы:
CREATE TABLE Persons (
id INTEGER NOT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
PRIMARY KEY (id));
CREATE TABLE Referees (
id INTEGER NOT NULL,
license_nbr VARCHAR(10) DEFAULT NULL NULL,
PRIMARY KEY (id),
CONSTRAINT referees_persons_fk
FOREIGN KEY (id)
REFERENCES Persons (id)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE Coaches (
id INTEGER NOT NULL,
license_nbr VARCHAR(10) DEFAULT NULL NULL,
PRIMARY KEY (id),
CONSTRAINT coaches_persons_fk
FOREIGN KEY (id)
REFERENCES Persons (id)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE Players (
id INTEGER NOT NULL,
registration_nbr VARCHAR(20) DEFAULT NULL NULL,
PRIMARY KEY (id),
CONSTRAINT players_persons_fk
FOREIGN KEY (id)
REFERENCES Persons (id)
ON DELETE CASCADE
ON UPDATE CASCADE);
Мои сокращенные классы сущностей:
@Entity
@Table(name = "Persons")
@Inheritance(strategy = InheritanceType.JOINED)
public class Person implements Serializable
{
@Id
@Column(name = "id")
private Integer id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
...
}
@Entity
@Table(name = "Referees")
public class Referee extends Person implements Serializable
{
@Column(name = "license_nbr")
private String licenseNbr = null;
...
}
@Entity
@Table(name = "Coaches")
public class Coach extends Person implements Serializable
{
@Column(name = "license_nbr")
private String licenseNbr = null;
...
}
@Entity
@Table(name = "Players")
public class Player extends Person implements Serializable
{
@Column(name = "registration_nbr")
private String registrationNbr = null;
...
}
Частичное наследование: сущности-лица могут существовать без соответствующих сущностей-судей, тренеров или игроков.
Непересекающееся наследование: может быть любое количество соответствующих подсущностей, то есть человек может быть судьей, тренером и игроком одновременно, возможно, в любой комбинации из трех. Каждая подтаблица может иметь ровно ни одного объекта или только один объект, но не несколько.
Обратите внимание, что поскольку наследование является частичным, Person не является абстрактным. Более того, у Person/s нет дискриминатора, потому что наследование не является непересекающимся.
Возможна ли такая модель в ORM Java? Как должны выглядеть аннотации?
У меня проблемы с поиском экземпляров, как я аннотировал классы, используя:
// Michael Jordan: the person who's only a player, too
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong Player instance
Person pe1 = em.find(Person.class, 1);
System.out.println("Loaded person = " + pe1);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct Player instance
Player pl1 = em.find(Player.class, 1);
System.out.println("Loaded player = " + pl1);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct null
Referee re1 = em.find(Referee.class, 1);
System.out.println("Loaded referee = " + re1);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct null
Coach ch1 = em.find(Coach.class, 1);
System.out.println("Loaded coach = " + ch1);
System.out.println();
System.out.println();
// Dirk Nowitzki: the person who's also a player *and* a referee
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong Player instance
Person pe2 = em.find(Person.class, 2);
System.out.println("Loaded person = " + pe2);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct Player instance
Player pl2 = em.find(Player.class, 2);
System.out.println("Loaded player = " + pl2);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong null
Referee re2 = em.find(Referee.class, 2);
System.out.println("Loaded referee = " + re2);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct null
Coach ch2 = em.find(Coach.class, 2);
System.out.println("Loaded coach = " + ch2);
System.out.println();
System.out.println();
// Blake Griffin: the person who's also a player, referee, *and* coach
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong Player instance
Person pe3 = em.find(Person.class, 3);
System.out.println("Loaded person = " + pe3);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (+1): correct Player instance
Player pl3 = em.find(Player.class, 3);
System.out.println("Loaded player = " + pl3);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong null
Referee re3 = em.find(Referee.class, 3);
System.out.println("Loaded referee = " + re3);
// EclipseLink 2.1.1 ( 1): ?
// EclipseLink 2.2.0 ( 1): ?
// Hibernate 3.6 (-1): wrong null
Coach ch3 = em.find(Coach.class, 3);
System.out.println("Loaded coach = " + ch3);
Ночная сборка EclipseLink 2.1.1 и 2.2.0 полностью терпит неудачу в EntityManager.find(...), в то время как Hibernate по крайней мере возвращает некоторые из ожидаемых экземпляров. Обратите внимание на слово «ожидается». Это мое понимание того, что должен делать JPA ORM, но я могу ошибаться.
Как видите, Hibernate всегда возвращает экземпляры подкласса Player, но не может найти экземпляры Coach и Referee, если экземпляр Player также доступен.
Итак, как JPA лучше всего справляется с этой моделью?