Apa "sisi kepemilikan" dalam pemetaan ORM?

129

Apa sebenarnya arti dari sisi pemilik ? Apa penjelasan dengan beberapa contoh pemetaan ( satu ke banyak, satu ke satu, banyak ke satu )?

Teks berikut ini adalah kutipan dari deskripsi dokumentasi @OneToOne di Java EE 6. Anda dapat melihat konsep memiliki sisi di dalamnya.

Menentukan asosiasi bernilai tunggal ke entitas lain yang memiliki multiplisitas satu-ke-satu. Biasanya tidak diperlukan untuk menentukan entitas target terkait secara eksplisit karena biasanya dapat disimpulkan dari jenis objek yang direferensikan. Jika hubungan adalah dua arah, sisi yang tidak memiliki harus menggunakan elemen yang dipetakan oleh penjelasan OneToOne untuk menentukan bidang hubungan atau properti dari sisi yang memiliki.

Pelajar saja
sumber
5
Saya tersesat sampai saya membaca ini: javacodegeeks.com/2013/04/…
darga33
2
Tabel DB dengan kolom kunci asing diperlakukan sebagai memiliki sisi. Jadi entitas bisnis yang menyatakan bahwa tabel DB adalah Pemilik (Pemilik-sisi) dari hubungan itu. Tidak perlu, tetapi sebagian besar kasus Owning-side akan memiliki penjelasan @JoinColumn.
Diablo

Jawaban:

202

Mengapa diperlukan gagasan tentang sisi kepemilikan:

Ide sisi kepemilikan dari hubungan dua arah datang dari fakta bahwa dalam database relasional tidak ada hubungan dua arah seperti dalam kasus objek. Dalam database kami hanya memiliki hubungan searah - kunci asing.

Apa alasan nama 'memiliki'?

Sisi kepemilikan relasi yang dilacak oleh Hibernate adalah sisi relasi yang dimiliki kunci asing dalam database.

Apa masalah yang dipecahkan oleh gagasan memiliki sisi?

Ambil contoh dua entitas yang dipetakan tanpa menyatakan sisi kepemilikan:

@Entity
@Table(name="PERSONS")
public class Person {
    @OneToMany
    private List<IdDocument>  idDocuments;
}

@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
    @ManyToOne
    private Person person;
}

Dari sudut pandang OO pemetaan ini mendefinisikan bukan hanya satu hubungan dua arah, tetapi dua terpisah.

Pemetaan akan membuat tidak hanya tabel PERSONSdanID_DOCUMENTS , tetapi juga akan membuat tabel asosiasi ketiga PERSONS_ID_DOCUMENTS:

CREATE TABLE PERSONS_ID_DOCUMENTS
(
  persons_id bigint NOT NULL,
  id_documents_id bigint NOT NULL,
  CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
  CONSTRAINT fk_docs FOREIGN KEY (id_documents_id) REFERENCES id_documents (id),
  CONSTRAINT pk UNIQUE (id_documents_id)
)

Perhatikan kunci utama pkaktifID_DOCUMENTS hanya . Dalam hal ini Hibernate melacak kedua sisi relasi secara independen: Jika Anda menambahkan dokumen ke relasi Person.idDocuments, ia menyisipkan catatan dalam tabel asosiasi PERSON_ID_DOCUMENTS.

Di sisi lain, jika kita memanggil idDocument.setPerson(person), kita mengubah person_id kunci asing di atas meja ID_DOCUMENTS. Hibernate membuat dua hubungan searah (kunci asing) pada database, untuk diimplementasikan salah satu relasi objek dua arah.

Bagaimana gagasan memiliki sisi memecahkan masalah:

Sering kali yang kita inginkan hanyalah kunci asing di atas meja ID_DOCUMENTS menujuPERSONS dan tabel asosiasi ekstra.

Untuk mengatasi ini, kita perlu mengkonfigurasi Hibernate untuk berhenti melacak modifikasi pada relasi Person.idDocuments. Hibernate seharusnya hanya melacak sisi lain dari relasi IdDocument.person, dan untuk itu kami menambahkan mappedBy :

@OneToMany(mappedBy="person")
private List<IdDocument>  idDocuments;

Apa artinya dipetakan oleh?

Ini berarti sesuatu seperti: "modifikasi pada sisi relasi ini sudah dipetakan. Di sisi lain relasi IdDocument.person, jadi tidak perlu melacaknya di sini secara terpisah di tabel tambahan."

Apakah ada GOTCHA, konsekuensinya?

Menggunakan mappedBy , Jika kita hanya memanggil person.getDocuments().add(document), kunci asing di ID_DOCUMENTSakan TIDAK dihubungkan ke dokumen baru, karena ini bukan pemilikan / sisi dilacak dari relasi!

Untuk menautkan dokumen dengan orang baru, Anda perlu menelepon secara eksplisit document.setPerson(person), karena itu adalah sisi pemiliknya relasi.

Saat menggunakan mappedBy , pengembang bertanggung jawab untuk mengetahui apa yang menjadi sisi pemiliknya , dan memperbarui sisi relasi yang benar untuk memicu kegigihan relasi baru dalam database.

Universitas Angular
sumber
17
Jawaban terbaik yang saya temukan yang menjelaskan Doktrin 'mappedBy' + 'inversedBy'.
Kurt Zhong
1
Terima kasih telah menentukan pemetaan & alasan di balik konsep ini.
Mohnish
1
Saya tidak tahu apakah semuanya telah berubah, tetapi pada Hibernate 5.0.9. Terakhir jika saya "hanya menelepon person.getDocuments().add(document)", hibernate memperbarui kunci asing ID_DOCUMENTS.
K.Nicholas
1
@Karl Nicholas, hai, setuju dengan Anda, kami memiliki atribut kaskade pada @OneToManyanotasi yang dapat diatur ke PERSIST dalam hal ini hibernate akan menyimpan semua entitas yang ditautkan ke DB. Adakah yang bisa menjelaskan ini - mengapa penulis mengatakan bahwa hibernate tidak akan melacak perubahan di sisi yang tidak memiliki - tetapi sebenarnya hibernasi melakukan pelacakan?
Oleksandr Papchenko
3
kaskade memberitahu penyedia untuk menyimpan entitas anak-anak bahkan jika entitas induk tidak memilikinya, sehingga secara efektif mengubah aturan. Jika Anda memiliki (atau memiliki) mappedBy = child.field dan TIDAK memiliki kaskade maka anak-anak dalam daftar tidak akan disimpan. Juga, jika Anda tidak memetakan. DAN tidak memiliki kaskade maka Orangtua memiliki hubungan dan jika Anda memasukkan anak-anak BARU dalam daftar dan kemudian menyimpan Orang Tua itu akan mengeluarkan pengecualian karena ID anak-anak baru tidak tersedia untuk disimpan di tabel gabung. Harapan yang mengklarifikasi hal-hal ... :)
K.Nicholas
142

Anda dapat membayangkan bahwa pihak yang memiliki adalah entitas yang memiliki referensi ke yang lain. Dalam kutipan Anda, Anda memiliki hubungan satu-ke-satu. Karena ini adalah hubungan simetris , Anda akan berakhir memiliki itu jika objek A dalam kaitannya dengan objek B maka sebaliknya juga benar.

Ini berarti bahwa menyimpan ke objek A referensi ke objek B dan menyimpan di objek B referensi ke objek A akan berlebihan: itu sebabnya Anda memilih objek "memiliki" yang lain memiliki referensi untuk itu.

Ketika Anda memiliki hubungan satu-ke-banyak, objek yang terkait dengan bagian "banyak" akan menjadi pihak yang memiliki, jika tidak, Anda harus menyimpan banyak referensi dari satu objek ke banyak. Untuk menghindari itu, setiap objek di kelas kedua akan memiliki pointer ke satu yang mereka rujuk (sehingga mereka adalah pihak yang memiliki).

Untuk hubungan banyak-ke-banyak, karena Anda akan memerlukan tabel pemetaan yang terpisah pula tidak akan ada sisi kepemilikan.

Kesimpulannya pihak yang memiliki adalah entitas yang memiliki referensi ke yang lain.

Mendongkrak
sumber
6
Terimakasih atas klarifikasi Anda.
Baru belajar
2
mungkin membantu untuk melihat di bawah ini juga jawaban saya untuk alasan nama 'dipetakan oleh' dan 'memiliki sisi', apa yang terjadi jika kita tidak mendefinisikan sisi kepemilikan, GOTCHA, harap itu membantu
Universitas Angular
5
Yah, jawabannya sebagian besar benar saya kira. Tetapi untuk Hibernate setidaknya, bahkan banyak-ke-banyak hubungan memiliki sisi kepemilikan. Ini memiliki implikasi untuk perilaku memperbarui misalnya. Lihat dari dekat bagian 4 ("Perbarui Hibernate Model Class") dari tutorial ini: viralpatel.net/blogs/…
Pfiver
11
Jawaban ini membingungkan lebih daripada membantu. Apa bagusnya mengatakan bahwa "Anda bisa membayangkan bahwa pihak yang memiliki adalah entitas yang memiliki referensi ke yang lain" ketika dalam hubungan dua arah, kedua objek Entitas akan memiliki referensi satu sama lain? Juga, "Untuk hubungan banyak-ke-banyak, karena Anda akan memerlukan tabel pemetaan terpisah bagaimanapun juga tidak akan ada sisi kepemilikan" sama sekali tidak benar: @ManyToManyhubungan memiliki sisi juga. Demikian pula, @OneToManyhubungan dapat menggunakan tabel bergabung, dan Anda masih harus menentukan sisi kepemilikan.
DavidS
5
Pada dasarnya, ini adalah jawaban lucu, merasa-baik yang memiliki suara naik karena lebih mudah dipahami daripada yang sebenarnya.
DavidS