Apa perbedaan antara Unidirectional and Bidirectional JPA dan Hibernate association?

146

Apa perbedaan antara asosiasi Searah dan Dua Arah?

Karena tabel yang dihasilkan di db semuanya sama, jadi satu-satunya perbedaan yang saya temukan adalah bahwa setiap sisi dari asosiasi dua arah akan merujuk ke yang lain, dan tidak searah.

Ini adalah asosiasi Searah

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}

public class Group {
    private int     id;
    private String  name;
}

Asosiasi dua arah

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}
public class Group {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="group")
    private List<User>  users;
}

Perbedaannya adalah apakah grup tersebut memiliki referensi pengguna.

Jadi saya bertanya-tanya apakah ini satu-satunya perbedaan? mana yang direkomendasikan?

hguser
sumber
9
Grup sekarang akan mengetahui pengguna mana di dalamnya. Saya tidak berpikir ini adalah perbedaan kecil.
Satadru Biswas
6
Hubungan dua arah menjadi kekacauan bagi saya ketika harus memperbarui. :)
diyoda_

Jawaban:

157

Perbedaan utamanya adalah bahwa hubungan dua arah menyediakan akses navigasi di kedua arah, sehingga Anda dapat mengakses sisi lain tanpa kueri eksplisit. Juga memungkinkan Anda untuk menerapkan opsi berjenjang ke kedua arah.

Perhatikan bahwa akses navigasi tidak selalu bagus, terutama untuk hubungan "satu-ke-sangat-banyak" dan "banyak-ke-sangat-banyak". Bayangkan sebuah Groupyang berisi ribuan Users:

  • Bagaimana Anda mengaksesnya? Dengan begitu banyak User, Anda biasanya perlu menerapkan beberapa pemfilteran dan / atau penomoran halaman, sehingga Anda tetap perlu menjalankan kueri (kecuali Anda menggunakan pemfilteran koleksi , yang menurut saya tampak seperti retasan). Beberapa pengembang mungkin cenderung menerapkan pemfilteran dalam memori dalam kasus seperti itu, yang jelas tidak baik untuk kinerja. Perhatikan bahwa memiliki hubungan seperti itu dapat mendorong pengembang semacam ini untuk menggunakannya tanpa mempertimbangkan implikasi kinerja.

  • Bagaimana Anda menambahkan Users baru ke Group? Untungnya, Hibernate melihat sisi hubungan pemilik saat mempertahankannya, jadi Anda hanya dapat menyetelnya User.group. Namun, jika Anda ingin menyimpan obyek dalam memori konsisten, Anda juga perlu menambahkan Useruntuk Group.users. Tapi itu akan membuat Hibernate mengambil semua elemen dari Group.usersdatabase!

Jadi, saya tidak setuju dengan rekomendasi dari Praktik Terbaik . Anda perlu merancang hubungan dua arah dengan hati-hati, dengan mempertimbangkan kasus penggunaan (apakah Anda memerlukan akses navigasi di kedua arah?) Dan kemungkinan implikasi kinerja.

Lihat juga:

axtavt
sumber
Hai, terima kasih, tampaknya Anda adalah ahli hibernasi, karena Anda telah menjawab pertanyaan saya: stackoverflow.com/questions/5350770/… . Dan sekarang saya tidak yakin hubungannya bertahan, karena saya tidak bisa menulis lebih banyak di komentar, jadi saya mempostingnya di sini dpaste.de/J85m. Silakan periksa jika memungkinkan. :)
hguser
@hguser: Jika Anda akhirnya memutuskan untuk membuat hubungan Anda dua arah, saya pikir akan lebih baik untuk menelepon setGroup()dari addUser()untuk menjaga kedua sisi konsisten.
axtavt
bagaimana jika saya tidak memanggil setGroup () di dalam group.addUser ()?
hguser
@hguser: Hubungan tidak akan dipertahankan, lihat poin 2 pada jawaban. Anda dapat memanggil setGroup()tanpa addUser(), tetapi itu akan menghasilkan status objek dalam memori yang tidak konsisten.
axtavt
Saya menemukan bahwa saya tidak dapat memetakan yang benar, dapatkah Anda meluangkan waktu untuk memeriksa proyek saya di github? ini adalah proyek kecil.
hguser
34

Ada dua perbedaan utama.

Mengakses sisi asosiasi

Yang pertama terkait dengan bagaimana Anda akan mengakses hubungan tersebut. Untuk pengaitan searah, Anda dapat menavigasi pengaitan dari satu ujung saja.

Jadi, untuk @ManyToOneasosiasi searah , itu berarti Anda hanya dapat mengakses hubungan dari sisi anak tempat kunci asing berada.

Jika Anda memiliki @OneToManyasosiasi searah , itu berarti Anda hanya dapat mengakses hubungan dari sisi induk yang mengelola kunci asing.

Untuk @OneToManypengaitan dua arah , Anda dapat menavigasi pengaitan dengan kedua cara, baik dari sisi induk atau dari sisi anak.

Anda juga perlu menggunakan metode tambah / hapus utilitas untuk asosiasi dua arah untuk memastikan bahwa kedua sisi disinkronkan dengan benar .

Performa

Aspek kedua terkait dengan kinerja.

  1. Karena @OneToMany, asosiasi searah tidak berkinerja sebaik asosiasi dua arah .
  2. Karena @OneToOne, asosiasi dua arah akan menyebabkan induk diambil dengan penuh semangat jika Hibernasi tidak dapat membedakan apakah Proxy harus ditetapkan atau nilai null .
  3. Sebab @ManyToMany, jenis koleksi membuat perbedaan cukup besar karena Setskinerjanya lebih baik daripadaLists .
Vlad Mihalcea
sumber
Tapi pihak orang tua selalu menjadi pihak yang memiliki kunci asing sejauh yang saya tahu. Dua kalimat ini sepertinya kontradiktif bagi saya. from the child side where the foreign key resides. from the parent side where the foreign key resides.
TOMAS
FK selalu berpihak pada anak-anak. OneToMany searah mengelola FK yang bisa ada di tabel anak di tabel gabungan. Ikuti tautan untuk lebih jelasnya.
Vlad Mihalcea
11

Dalam hal pengkodean, hubungan dua arah lebih kompleks untuk diterapkan karena aplikasi bertanggung jawab untuk menjaga kedua sisi selaras sesuai dengan spesifikasi JPA 5 (pada halaman 42). Sayangnya contoh yang diberikan dalam spesifikasi tidak memberikan detail lebih lanjut, sehingga tidak memberikan gambaran tingkat kerumitannya.

Saat tidak menggunakan cache tingkat kedua, biasanya bukan masalah jika metode hubungan tidak diimplementasikan dengan benar karena instance akan dibuang di akhir transaksi.

Saat menggunakan cache tingkat kedua, jika ada yang rusak karena metode penanganan hubungan yang diterapkan secara salah, ini berarti bahwa transaksi lain juga akan melihat elemen yang rusak (cache tingkat kedua bersifat global).

Hubungan dua arah yang diterapkan dengan benar dapat membuat kueri dan kode lebih sederhana, tetapi tidak boleh digunakan jika tidak masuk akal dalam hal logika bisnis.

Constantino Cronemberger
sumber
9

Saya tidak 100% yakin ini satu - satunya perbedaan, tetapi inilah perbedaan utama . Juga direkomendasikan untuk memiliki asosiasi dua arah oleh dokumen Hibernate:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Secara khusus:

Lebih suka asosiasi dua arah: Asosiasi searah lebih sulit untuk ditanyakan. Dalam aplikasi besar, hampir semua pengaitan harus dinavigasi di kedua arah dalam kueri.

Saya pribadi memiliki sedikit masalah dengan rekomendasi selimut ini - menurut saya ada kasus di mana seorang anak tidak memiliki alasan praktis untuk mengetahui tentang induknya (misalnya, mengapa suatu item pesanan perlu mengetahui tentang pesanannya? terkait dengan?), tetapi saya juga melihat nilai di dalamnya dalam porsi waktu yang wajar. Dan karena dua arah tidak benar-benar merugikan apa pun, saya tidak merasa terlalu keberatan untuk dipatuhi.

kvista
sumber
Dua arah dapat merugikan dalam beberapa kasus, seperti yang telah dijelaskan axtavt! Saya akan sangat berhati-hati dengan setiap hubungan yang dipetakan dalam entitas Hibernate! Anda bisa berakhir dengan waktu yang tidak terbatas untuk memuat sesuatu di Hibernate, kecuali Anda tahu persis apa yang Anda lakukan. Pikirkan baik-baik tentang kasus penggunaan dan gunakan kelas model yang berbeda untuk kasus penggunaan yang berbeda. F.ex. dalam daftar hal, saya tidak memerlukan semua objek terkait, hanya label dan ID. Jadi entitas daftar berbeda (dan sangat sederhana) dari entitas detail, bagi saya.
cslotty