JPA @OneToOne z Shared ID - Czy Mogę to zrobić lepiej? [odpowiedz]

Pracuję z istniejącym schematem, którego wolałbym nie zmieniać. Schemat ma relację jeden do jednego między tabelami Person I VitalStats, gdzie Person ma klucz podstawowy, a VitalStats używa tego samego pola, co zarówno Klucz podstawowy, jak i klucz obcy dla osoby, co oznacza, że jego wartość jest wartością odpowiadającą PK osoby.

Te rekordy są tworzone przez zewnętrzne procesy, a mój kod JPA nigdy nie musi aktualizować VitalStats. Dla mojego modelu obiektowego chciałbym, aby moja klasa Person zawiera element VitalStats, ale:

Kiedy próbuję

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

Mam problem, że VitalStats nie ma @ Id, co nie działa dla @ Entity.\

If I try

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

To rozwiązuje problem @Id, ale wymaga, aby ta osoba była Serializowalna. Wrócimy do tego.

Mógłbym zrobić VitalStats @ Embeddable i podłączyć go do osoby za pomocą @ ElementCollection, ale wtedy musiałby być dostępny jako kolekcja, chociaż wiem, że jest tylko jeden element. Wykonalne, ale jednocześnie trochę denerwujące i trochę mylące.

Więc co mnie powstrzymuje przed tym, że ta osoba implementuje Serializable? Nic, naprawdę, poza tym, że lubię, aby wszystko w moim kodzie było tam z jakiegoś powodu, i nie widzę w tym żadnej logiki, co sprawia, że mój kod jest mniej czytelny.

W międzyczasie zamieniłem pole Person w VitalStats na long personId i zrobiłem @Id VitalStats, więc teraz działa @OneToOne.

Wszystkie te rozwiązania tego, co wydaje mi się (jak dla mnie) prostym problemem, są trochę niezgrabne, więc zastanawiam się, czy czegoś mi brakuje, czy może ktoś mi chociaż wyjaśnić, dlaczego osoba musi być Serializowalna.

TIA

Author: Manuel Drieschmanns, 2011-07-26

2 answers

Aby odwzorować asocjację jeden do jednego za pomocą współdzielonych kluczy głównych, użyj adnotacji @PrimaryKeyJoinColumn i @MapsId.

Odpowiednie sekcje dokumentacji referencyjnej Hibernate:

PrimaryKeyJoinColumn

Adnotacja PrimaryKeyJoinColumn mówi, że klucz główny jednostka jest używana jako wartość klucza obcego dla jednostki powiązanej.

MapsId

Adnotacja MapsId prosi Hibernate o skopiowanie identyfikatora z inny podmiot powiązany. W żargonie Hibernate jest znany jako generator zagraniczny, ale mapowanie JPA czyta się lepiej i jest zachęcane

osób.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;
}

Baza Danych Osób Tabela

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

Tabela Bazy Danych VitalStats

CREATE TABLE  vitalstats 
(
  vitalstats_id  bigint(20) NOT NULL,
  stats          varchar(255) default NULL,
  PRIMARY KEY  (`vitalstats_id`)
)
 79
Author: Joel Hudon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-15 11:09:00

W moim przypadku to zrobił sztuczkę:

Klasa nadrzędna:

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

Klasa dziecka:

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;
}
 11
Author: camposer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-10 09:44:51