Hubungan Satu-ke-Satu di JPA

1. Pengenalan

Dalam tutorial ini, kita akan melihat pelbagai cara untuk membuat pemetaan satu lawan satu di JPA.

Kami memerlukan pemahaman asas mengenai kerangka Hibernate, jadi sila lihat Panduan Hibernate 5 dengan Spring untuk latar belakang tambahan.

2. Penerangan

Anggaplah kita membina Sistem Pengurusan Pengguna dan bos kami meminta kami menyimpan alamat surat untuk setiap pengguna. Pengguna akan mempunyai satu alamat surat-menyurat, dan alamat surat-menyurat hanya akan mempunyai satu pengguna yang terkait dengannya.

Ini adalah contoh hubungan satu lawan satu, dalam kes ini antara entiti pengguna dan alamat .

Mari lihat bagaimana kita dapat melaksanakannya di bahagian berikutnya.

3. Menggunakan Kunci Asing

3.1. Pemodelan dengan Kunci Asing

Mari lihat rajah ER berikut yang mewakili pemetaan satu lawan satu berdasarkan kunci asing:

Dalam contoh ini, address_id lajur dalam pengguna adalah kunci asing untuk alamat .

3.2. Melaksanakan dengan Kunci Asing dalam JPA

Pertama, mari buat kelas Pengguna dan beri komen dengan tepat:

@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "address_id", referencedColumnName = "id") private Address address; // ... getters and setters } 

Perhatikan bahawa kami meletakkan anotasi @OneToOne pada bidang entiti yang berkaitan, Alamat .

Juga, kita perlu meletakkan anotasi @JoinColumn untuk mengkonfigurasi nama lajur di jadual pengguna yang memetakan ke kunci utama dalam jadual alamat . Sekiranya kami tidak memberikan nama, maka Hibernate akan mengikuti beberapa peraturan untuk memilih yang lalai.

Akhirnya, perhatikan di entiti seterusnya bahawa kami tidak akan menggunakan anotasi @JoinColumn di sana. Ini kerana kita hanya perlu pada yang memiliki sisi hubungan kunci asing. Ringkasnya, sesiapa sahaja yang mempunyai lajur kunci asing mendapat anotasi @JoinColumn .

The Alamat entiti ternyata agak mudah:

@Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "address") private User user; //... getters and setters }

Kita juga perlu meletakkan anotasi @OneToOne di sini. Ini kerana ini adalah hubungan dua arah. Bahagian alamat hubungan disebut sisi bukan pemilik .

4. Menggunakan Kekunci Utama Bersama

4.1. Pemodelan dengan Kekunci Utama Bersama

Dalam strategi ini, bukannya membuat address_id lajur baru , kami akan menandakan kunci utamalajur (user_id) daripada Rajah address sebagai kunci asing kepada pengguna Rajah :

Kami telah mengoptimumkan ruang simpanan dengan memanfaatkan hakikat bahawa entiti ini mempunyai hubungan satu sama lain di antara mereka.

4.2. Melaksanakan dengan Kunci Utama Bersama dalam JPA

Perhatikan bahawa definisi kami hanya berubah sedikit:

@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private Address address; //... getters and setters }
@Entity @Table(name = "address") public class Address { @Id @Column(name = "user_id") private Long id; //... @OneToOne @MapsId @JoinColumn(name = "user_id") private User user; //... getters and setters } 

The mappedBy atribut kini berpindah ke pengguna kelas sejak kunci asing kini hadir di alamat meja. Kami juga telah menambah yang @PrimaryKeyJoinColumn anotasi, yang menunjukkan bahawa kunci utama daripada penggunaan entiti akan digunakan sebagai nilai utama yang asing bagi bersekutu Alamat entiti .

Kami masih harus menentukan medan @Id di kelas Alamat tetapi perhatikan ini merujuk pada lajur user_id , dan tidak lagi menggunakan anotasi @GeneratedValue . Juga, di padang itu rujukan yang pengguna , kami telah menambah yang @MapsId anotasi, yang menunjukkan bahawa nilai kunci primer akan disalin dari pengguna entiti.

5. Menggunakan Jadual Gabung

Pemetaan satu lawan satu boleh terdiri daripada dua jenis - Pilihan dan Wajib . Setakat ini, kami hanya melihat hubungan wajib.

Sekarang, mari kita bayangkan bahawa pekerja kita mempunyai kaitan dengan stesen kerja. Itu satu-satu, tetapi kadang-kadang pekerja mungkin tidak mempunyai stesen kerja dan sebaliknya.

5.1. Pemodelan dengan Jadual Gabung

Strategi yang telah kita bincangkan hingga sekarang memaksa kita untuk meletakkan nilai nol di ruang untuk menangani hubungan pilihan .

Biasanya, kita memikirkan hubungan banyak-ke-banyak ketika kita mempertimbangkan jadual bergabung, tetapi, dengan menggunakan jadual bergabung, dalam hal ini, dapat membantu kita menghilangkan nilai nol ini:

Sekarang, setiap kali kita mempunyai hubungan, kita akan membuat entri di meja stesen_pekerjaan dan mengelakkan nolkesemuanya.

5.2. Melaksanakan dengan Jadual Gabung di JPA

Contoh pertama kami menggunakan @JoinColumn. Kali ini, kami akan menggunakan @JoinTable :

@Entity @Table(name = "employee") public class Employee { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "emp_workstation", joinColumns = { @JoinColumn(name = "employee_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "workstation_id", referencedColumnName = "id") }) private WorkStation workStation; //... getters and setters }
@Entity @Table(name = "workstation") public class WorkStation { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "workStation") private Employee employee; //... getters and setters }

@ JoinTable mengarahkan Hibernate untuk menggunakan strategi join table sambil mengekalkan hubungan.

Juga, Pekerja adalah pemilik hubungan ini kerana kami memilih untuk menggunakan penjelasan jadual bergabung di atasnya.

6. Kesimpulannya

Dalam tutorial ini, kami mempelajari pelbagai cara untuk mengekalkan hubungan satu lawan satu di JPA dan Hibernate dan kapan menggunakannya.

Kod sumber tutorial ini boleh didapati di GitHub.