Anotasi mana yang harus saya gunakan: @IdClass atau @EmbeddedId

128

Spesifikasi JPA(Java Persistence API) memiliki 2 cara berbeda untuk menentukan kunci komposit entitas: @IdClassdan @EmbeddedId.

Saya menggunakan kedua anotasi pada entitas yang dipetakan, tetapi ternyata menjadi kekacauan besar bagi orang-orang yang tidak terlalu mengenal JPA.

Saya hanya ingin mengadopsi satu cara untuk menentukan kunci komposit. Yang mana yang benar-benar yang terbaik? Mengapa?

sakana
sumber

Jawaban:

86

Saya menganggap itu @EmbeddedIdmungkin lebih verbose karena dengan @IdClassAnda tidak dapat mengakses seluruh objek kunci utama menggunakan operator akses bidang apa pun. Menggunakan @EmbeddedIdAnda dapat melakukannya seperti ini:

@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
  @EmbeddedId EmployeeId employeeId;
  ...
}

Ini memberikan gagasan yang jelas tentang bidang yang membuat kunci komposit karena semuanya dikumpulkan dalam kelas yang diakses melalui operator akses lapangan.

Perbedaan lain dengan @IdClassdan @EmbeddedIdadalah ketika menulis HQL:

Dengan @IdClassAnda menulis:

pilih e.name dari Karyawan e

dan dengan @EmbeddedIdAnda harus menulis:

pilih e.employeeId.name dari Karyawan e

Anda harus menulis lebih banyak teks untuk kueri yang sama. Beberapa orang mungkin berpendapat bahwa ini berbeda dari bahasa yang lebih alami seperti yang dipromosikan oleh IdClass. Tetapi sebagian besar waktu memahami langsung dari permintaan bahwa bidang yang diberikan adalah bagian dari kunci komposit adalah bantuan yang sangat berharga.

Jorge Ferreira
sumber
10
Meskipun saya setuju dengan penjelasan yang diberikan di atas saya juga ingin menambahkan satu use case unik untuk @IdClasswalaupun saya lebih suka @EmbeddedIddalam kebanyakan situasi (Mengetahui hal ini dari sesi oleh Antonio Goncalves. Apa yang dia sarankan adalah kita dapat menggunakan @IdClassdalam kasus komposit kelas kunci tidak dapat diakses atau datang dari modul lain atau kode warisan di mana kita tidak dapat menambahkan anotasi. Dalam skenario itu @IdClassakan memberi kita cara kita.
Gaurav Rawat
1
Saya pikir itu mungkin bahwa kasus-kasus untuk menggunakan @IdClassanotasi yang diberikan oleh @Gaurav adalah alasan mengapa spesifikasi JPA mencantumkan kedua metode untuk membuat kunci komposit .. @IdClassdan@EmbeddidId
kapad
20

Ada tiga strategi untuk menggunakan kunci utama majemuk:

  • Tandai sebagai @Embeddabledan tambahkan ke kelas entitas Anda properti normal untuknya, ditandai dengan @Id.
  • Tambahkan ke kelas entitas Anda properti normal untuknya, ditandai dengan @EmbeddedId.
  • Tambahkan properti ke kelas entitas Anda untuk semua bidangnya, tandai dengan @Id, dan tandai kelas entitas Anda @IdClass, dengan menyediakan kelas kelas kunci utama Anda.

Penggunaan @Iddengan kelas ditandai sebagai @Embeddablependekatan yang paling alami. The @Embeddabletag dapat digunakan untuk nilai-nilai non primary key embeddable pula. Ini memungkinkan Anda untuk memperlakukan kunci utama majemuk sebagai properti tunggal, dan memungkinkan penggunaan kembali @Embeddablekelas di tabel lain.

Pendekatan paling alami berikutnya adalah penggunaan @EmbeddedIdtag. Di sini, kelas kunci utama tidak dapat digunakan dalam tabel lain karena itu bukan @Embeddableentitas, tetapi memungkinkan kita untuk memperlakukan kunci sebagai atribut tunggal dari beberapa kelas.

Akhirnya, penggunaan @IdClassdan @Idanotasi memungkinkan kita untuk memetakan kelas kunci primer majemuk menggunakan properti entitas itu sendiri yang sesuai dengan nama properti di kelas kunci primer. Nama-nama harus sesuai (tidak ada mekanisme untuk mengesampingkan ini), dan kelas kunci utama harus menghormati kewajiban yang sama dengan dua teknik lainnya. Satu-satunya keuntungan dari pendekatan ini adalah kemampuannya untuk "menyembunyikan" penggunaan kelas kunci utama dari antarmuka entitas yang melampirkan. The @IdClasspenjelasan mengambil parameter nilai tipe Class, yang harus menjadi kelas yang akan digunakan sebagai kunci utama senyawa. Bidang yang sesuai dengan properti kelas kunci utama yang akan digunakan harus semua dijelaskan dengan @Id.

Referensi: http://www.apress.com/us/book/9781430228509

Adelin
sumber
17

Saya menemukan contoh di mana saya harus menggunakan EmbeddedId bukan IdClass. Dalam skenario ini ada tabel bergabung yang memiliki kolom tambahan yang ditentukan. Saya mencoba untuk memecahkan masalah ini menggunakan IdClass untuk mewakili kunci dari entitas yang secara eksplisit mewakili baris dalam tabel bergabung. Saya tidak bisa membuatnya bekerja dengan cara ini. Syukurlah "Java Persistence With Hibernate" memiliki bagian yang didedikasikan untuk topik ini. Salah satu solusi yang diusulkan sangat mirip dengan saya tetapi menggunakan EmbeddedId sebagai gantinya. Saya memodelkan objek saya setelah yang ada di buku itu sekarang berperilaku dengan benar.

laz
sumber
13

Sejauh yang saya tahu jika komposit PK Anda mengandung FK lebih mudah dan lebih mudah digunakan @IdClass

Dengan @EmbeddedIdAnda harus menetapkan pemetaan untuk kolom FK Anda dua kali, masuk @Embeddedabledan sekali lagi sebagai contoh, di @ManyToOnemana @ManyToOneharus dibaca-saja ( @PrimaryKeyJoinColumn) karena Anda tidak dapat memiliki satu kolom yang diatur dalam dua variabel (kemungkinan konflik).
Jadi, Anda harus mengatur FK Anda menggunakan tipe sederhana di @Embeddedable.

Di situs lain menggunakan @IdClasssituasi ini dapat ditangani lebih mudah seperti yang ditunjukkan di Kunci Primer melalui OneToOne dan Hubungan ManyToOne :

Contoh anotasi id JPA 2.0 ManyToOne

...
@Entity
@IdClass(PhonePK.class)
public class Phone {

    @Id
    private String type;

    @ManyToOne
    @Id
    @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...
}

Contoh kelas id JPA 2.0

...
public class PhonePK {
    private String type;
    private long owner;

    public PhonePK() {}

    public PhonePK(String type, long owner) {
        this.type = type;
        this.owner = owner;
    }

    public boolean equals(Object object) {
        if (object instanceof PhonePK) {
            PhonePK pk = (PhonePK)object;
            return type.equals(pk.type) && owner == pk.owner;
        } else {
            return false;
        }
    }

    public int hashCode() {
        return type.hashCode() + owner;
    }
}
Ondrej Bozek
sumber
1
Hanya saja, jangan lupa menambahkan getter ke kelas PK Anda
Sonata
@Sonata mengapa kita membutuhkan getter? Saya mencobanya tanpa getter / setter dan berfungsi dengan baik
xagaffar
Terima kasih atas contoh kelas id! Meskipun akhirnya saya perlu mengimplementasikan Serializable juga. Juga mungkin menambahkan getter dan setter, terutama jika IDE Anda dapat secara otomatis menghasilkannya.
Starwarswii
8

Saya pikir keuntungan utama adalah bahwa kita dapat menggunakan @GeneratedValueid saat menggunakan @IdClass? Saya yakin kita tidak bisa menggunakan @GeneratedValueuntuk @EmbeddedId.

bertie
sumber
1
Apakah tidak mungkin menggunakan @GeneratedValue di Embeddedid ??
Kayser
1
Saya telah menggunakannya dengan sukses dengan EmbeddedId tetapi ternyata dukungannya bervariasi menurut DB. Ini juga benar tentang menggunakannya dengan IdClass. Spesifikasinya mengatakan: "Anotasi GeneratedValue hanya dapat digunakan secara portable untuk kunci primer sederhana (yaitu, non-komposit)."
BPS
4

Kunci Komposit tidak boleh memiliki @Idproperti saat @EmbeddedIddigunakan.

BK
sumber
1

Dengan EmbeddedId Anda dapat menggunakan klausa IN di HQL, misalnya: di FROM Entity WHERE id IN :idsmana id adalah EmbeddedId sedangkan itu sakit untuk mencapai hasil yang sama dengan IdClass Anda akan ingin melakukan sesuatu sepertiFROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

Aleks Ben Maza
sumber