Tidak dapat menggunakan pembuatan kunci kolom identitas dengan <union-subclass> (TABLE_PER_CLASS)

97

com.something.SuperClass:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class SuperClass implements Serializable {
    private static final long serialVersionUID = -695503064509648117L;

    long confirmationCode;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // Causes exception!!!
    public long getConfirmationCode() {
        return confirmationCode;
    }

    public void setConfirmationCode(long confirmationCode) {
        this.confirmationCode = confirmationCode;
    }
}

com.something.SubClass:

@Entity
public abstract class Subclass extends SuperClass {
    private static final long serialVersionUID = 8623159397061057722L;

    String name;

    @Column(nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Beri saya pengecualian ini:

Caused by: org.hibernate.MappingException: Cannot use identity column key
generation with <union-subclass> mapping for: com.something.SuperClass

Apa cara terbaik dan paling nyaman bagi saya untuk menghasilkan ID? Saya tidak ingin mengubah strategi warisan saya.

Martijn Pieters
sumber

Jawaban:

231

Masalahnya di sini adalah Anda mencampur pewarisan "tabel per kelas" dan GenerationType.Auto. Pertimbangkan kolom identitas di MsSQL. Ini berbasis kolom. Dalam strategi "tabel per kelas", Anda menggunakan satu tabel per kelas dan masing-masing memiliki ID.

Mencoba:

@GeneratedValue(strategy = GenerationType.TABLE)

zoidbeck
sumber
2
Solusi Sempurna. Bahkan forum Hibernate tampaknya tidak memiliki solusi ini, dan mereka membahas topik forum.hibernate.org/…
Spring Monkey
1
Apakah masalah ini hanya dengan MySql atau biasa saat saya menonton salah satu video untuk Tabel per pendekatan kelas dan itu bekerja dengan baik di postgres yang digunakan
Prashant
1
Saya mengalami ini baru-baru ini saat menguji aplikasi Dropwizard. Dalam kasus saya, saya mengatasinya dengan memastikan untuk menggunakan opsi konfigurasi yang sama yang digunakan oleh DW untuk membuat pabrik sesi. Saya cukup yakin menyetel properti "hibernate.id.new_generator_mappings" menjadi true adalah yang memperbaikinya. Ini adalah DW 0.7.0, Hibernate 4.3.1, DB adalah H2.
sfitts
1
Ini bekerja dengan sempurna. Namun, sangat disarankan untuk tidak memilih menggunakan strategi pembuatan id 'TABLE' karena ini memicu banyak kueri (pilih, sisipkan, dan perbarui) dan pertahankan kunci untuk menghasilkan nilai unik untuk kunci utama. Jadi apa solusi alternatif untuk ini jika kita memiliki skenario Warisan yang agak besar? Ini pasti akan berdampak besar pada kinerja.
MAC
8

Saya ingin tahu apakah ini adalah masalah khusus dialek database, karena menonton tutorial youtube dengan PostgreSQL sebagai database yang mendasarinya, saya melihat bahwa pembuat video berhasil menjalankan aplikasi dengan default @GeneratedValue. Dalam kasus saya (database yang mendasarinya adalah MySQL), saya harus memodifikasi strategi @GeneratedValue menjadi GenerationType.TABLE persis seperti yang diusulkan zoidbeck.

Ini videonya: https://www.youtube.com/watch?v=qIdM4KQOtH8

skiabox
sumber
Postgres dapat melakukan pewarisan sehingga Anda mungkin benar bahwa ini adalah database spesifik: postgresql.org/docs/8.1/static/ddl-inherit.html Video tidak menjelaskan (atau saya melewatkannya) bagaimana skema dibuat. Jadi mungkin dialek postgres NHibernate dapat melakukannya sendiri atau sebaliknya Anda harus menambahkan 'INHERITS' secara manual. Sebenarnya saya tidak tahu.
zoidbeck
6
Di PostgreSQL, Hibernate default untuk digunakan GenerationType.SEQUENCE. Itulah mengapa ia bekerja secara otomatis di sana. Ini sama sekali tidak ada hubungannya dengan PostgreSQL INHERITS.
Henning
Saya telah menggunakan tutorial yang sama & menggunakan @Generated menyebabkan masalah karena saya menggunakan MySql. Menghabiskan banyak waktu debugging sampai saya melihat posting ini
Deen John
5

Setuju dengan jawaban zoidbeck. Anda perlu mengubah strategi menjadi:

@GeneratedValue(strategy = GenerationType.TABLE)

Tapi bukan itu saja, Anda perlu membuat tabel baru, yang akan menampung urutan kunci primer tabel abstrak Anda. Ubah pemetaan Anda menjadi

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "ConfirmationCodeGenerator")
@TableGenerator(table = "SEQUENCES", name = "ConfirmationCodeGenerator")
public long getConfirmationCode() {
   return confirmationCode;
}

Dan tabel baru dalam database akan terlihat seperti berikut: masukkan deskripsi gambar di sini

Ketika Anda menjalankan aplikasi Anda, Hibernate akan memasukkan baris di mana sequence_nameakan menjadi nama entitas ( SuperClassdalam contoh ini) dan sequence_next_hi_valuenilai akan secara otomatis bertambah dan digunakan untuk catatan baru dari semua tabel subclass yang mengimplementasikan.

Gondy
sumber
2

Dalam kasus kami, kami menggunakan database PostreSQL untuk dev dan produksi dan database hsqldb dalam memori untuk pengujian. Kami menggunakan urutan dalam kedua kasus untuk menghasilkan id. Tampaknya GenerationType.AUTOdefault SEQUENCEuntuk postgres, tetapi gagal dalam tes lokal kami (harus default ke sesuatu yang lain untuk hsqldb).

Jadi solusi yang berhasil untuk kami, gunakan secara eksplisit GenerationType.SEQUENCE.

Ryan Walls
sumber
1

Anda dapat menggunakan @MappedSuperclass untuk pewarisan

leimbag
sumber
0

Ada Kepatuhan standar SQL di antara MySQL dan PostgreSQL. PostgreSQL Postgres memahami subset SQL92 / 99 yang baik ditambah beberapa fitur berorientasi objek ke subset ini. Postgres mampu menangani rutinitas dan aturan yang kompleks sebagai kueri SQL deklaratif, subkueri, tampilan, dukungan multi-pengguna, transaksi, pengoptimalan kueri, pewarisan, dan array. Tidak mendukung pemilihan data di berbagai database.

MySQL MySQL menggunakan SQL92 sebagai dasarnya. Berjalan di platform yang tak terhitung jumlahnya. Mysql dapat membuat kueri yang dapat menggabungkan tabel dari database yang berbeda. Mendukung gabungan luar kiri dan kanan menggunakan sintaks ANSI dan ODBC. Sejak MySQL 4.1 sejak rilis itu, MySQL akan menangani subkueri. Tampilan didukung pada rilis 5.

Untuk penjelasan rinci, silakan kunjungi. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html

Coderac
sumber
Tolong jangan merasa buruk tentang ini, tetapi saya pikir perbandingan MySQL dan PostgreSQL tidak relevan dengan topik (meskipun default Hibernate berbeda untuk mereka).
mrts