Подтвердить что ты не робот

JPA @OneToOne с общим ID - Могу ли я сделать это лучше?

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

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

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

@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, который не работает для @Entity.\

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

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

который решает проблему @Id, но требует, чтобы Person был Serializable. Хорошо, вернемся к этому.

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

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

Тем временем я просто заменил поле Person в VitalStats длинным personId и сделал VitalStatss @Id, так что теперь работает @OneToOne.

Все эти решения, которые кажутся мне похожими на простые проблемы, немного неуклюжи, поэтому я задаюсь вопросом, не пропадает ли я что-нибудь или кто-то может хотя бы объяснить мне, почему Person должен быть Serializable.

ТИА

4b9b3361

Ответ 1

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

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

PrimaryKeyJoinColumn

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

MapsId

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

Person.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;
}

Таблица базы данных Person

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`)
)

Ответ 2

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

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

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