JPA @OneToOne с общим идентификатором-могу ли я сделать это лучше?


Я работаю с существующей схемой, которую я бы предпочел не менять. Схема имеет взаимно однозначное отношение между таблицами Person и VitalStats, где Person имеет первичный ключ, а VitalStats использует то же поле, что и его первичный ключ и его внешний ключ для Person, то есть его значение является значением соответствующего ПК человека.

эти записи создаются внешними процессами, и мой код JPA никогда не нуждается в обновлении VitalStats. Для моей объектной модели мне нужен мой человек класс, содержащий член VitalStats, но:

когда я пытаюсь

@Entity
public class Person{
    private long id;
    @Id
    public long getId(){ return id; }

    private VitalStats vs;
    @OneToOne(mappedBy = “person”)
    public VitalStats getVs() { return vs; }
}

@Entity
    public class VitalStats{
     private Person person;
    @OneToOne
    public Person getPerson() { return person; }
}

у меня есть проблема, что VitalStats не хватает @Id, который не работает для @сущности.

Если я попробую

@Id @OneToOne
public Person getPerson() { return person; }

это решает проблему @Id, но требует, чтобы человек был Сериализуемым. Мы еще вернемся к этому.

я мог бы сделать VitalStats @Embeddable и подключить его к человеку через @ ElementCollection, но тогда он должен быть доступен как коллекция, даже хотя я знаю, что есть только один элемент. Выполнимо, но и немного раздражает и немного сбивает с толку.

Так что мешает мне просто сказать, что человек реализует Serializable? На самом деле ничего, кроме того, что мне нравится, чтобы все в моем коде было по какой-то причине, и я не вижу никакой логики в этом, что делает мой код менее читаемым.

тем временем я просто заменил поле Person в VitalStats на длинный personId и сделал этот идентификатор @ID VitalStats, поэтому теперь @OneToOne работает.

все эти решения для того, что кажется (мне) простой проблемой, немного неуклюжи, поэтому мне интересно, не пропущу ли я что-нибудь, или кто-то может хотя бы объяснить мне, почему человек должен быть Сериализуемым.

ТИА

2 53

2 ответа:

чтобы сопоставить связь один к одному с помощью общих первичных ключей используйте @PrimaryKeyJoinColumn и @MapsId Примечание.

соответствующие разделы справочной документации Hibernate:

PrimaryKeyJoinColumn

в аннотации PrimaryKeyJoinColumn говорится, что первичный ключ объект используется в качестве значения внешнего ключа в связанной сущности.

MapsId

в MapsId аннотации задать спящий режим, чтобы скопировать идентификатор из другая связанная сущность. В гибернации жаргоне, это называется иностранный генератор, но отображение JPA читается лучше и поощряется

человек.java

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "person_id")
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private VitalStats vitalStats;       
}

VitalStats.java

@Entity
public class VitalStats 
{
    @Id @Column(name="vitalstats_id") Long id;

    @MapsId 
    @OneToOne(mappedBy = "vitalStats")
    @JoinColumn(name = "vitalstats_id")   //same name as id @Column
    private Person person;

    private String stats;
}

Таблица Базы Данных Лиц

CREATE TABLE  person (
  person_id   bigint(20) NOT NULL auto_increment,
  name        varchar(255) default NULL,
  PRIMARY KEY  (`person_id`)
) 

База Данных VitalStats Таблица

CREATE TABLE  vitalstats 
(
  vitalstats_id  bigint(20) NOT NULL,
  stats          varchar(255) default NULL,
  PRIMARY KEY  (`vitalstats_id`)
)

в моем случае это сделал трюк:

родительский класс:

public class User implements Serializable {
  private static final long serialVersionUID = 1L;

  /** auto generated id (primary key) */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(unique = true, nullable = false)
  private Long id;

  /** user settings */
  @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
  private Setting setting;
}

дочерний класс:

public class Setting implements Serializable {
  private static final long serialVersionUID = 1L;

  /** setting id = user id */
  @Id
  @Column(unique = true, nullable = false)
  private Long id;

  /** user with this associated settings */
  @MapsId
  @OneToOne
  @JoinColumn(name = "id")
  private User user;
}