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
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:
Adnotacja PrimaryKeyJoinColumn mówi, że klucz główny jednostka jest używana jako wartość klucza obcego dla jednostki powiązanej.
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`)
)
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;
}
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