Apa cara terbaik untuk mendapatkan entitas dengan bidang tipe Daftar tetap?
Command.java
package persistlistofstring;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Basic
List<String> arguments = new ArrayList<String>();
public static void main(String[] args) {
Command command = new Command();
EntityManager em = Persistence
.createEntityManagerFactory("pu")
.createEntityManager();
em.getTransaction().begin();
em.persist(command);
em.getTransaction().commit();
em.close();
System.out.println("Persisted with id=" + command.id);
}
}
Kode ini menghasilkan:
> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack:
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
> at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
> at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
> at persistlistofstring.Command.main(Command.java:30)
> Caused by:
> ...
Maaf untuk menghidupkan kembali utas lama tetapi jika ada yang mencari solusi alternatif tempat Anda menyimpan daftar string Anda sebagai satu bidang dalam basis data Anda, inilah cara saya menyelesaikannya. Buat Konverter seperti ini:
Sekarang gunakan di Entitas Anda seperti ini:
Dalam database daftar Anda akan disimpan sebagai foo; bar; foobar dan di objek Java Anda, Anda akan mendapatkan daftar dengan string tersebut.
Semoga ini bermanfaat bagi seseorang.
sumber
SPLIT_CHAR
kejadian di string Anda.Jawaban ini dibuat sebelum implementasi JPA2, jika Anda menggunakan JPA2, lihat jawaban ElementCollection di atas:
Daftar objek di dalam objek model umumnya dianggap hubungan "OneToMany" dengan objek lain. Namun, sebuah String bukan (dengan sendirinya) klien yang diijinkan dari hubungan Satu-ke-Banyak, karena tidak memiliki ID.
Jadi, Anda harus mengonversi daftar Strings Anda ke daftar objek JPA Argument-class yang berisi ID dan String. Anda bisa berpotensi menggunakan String sebagai ID, yang akan menghemat sedikit ruang di tabel Anda baik dari menghapus bidang ID dan dengan mengkonsolidasikan baris di mana String sama, tetapi Anda akan kehilangan kemampuan untuk memesan argumen kembali ke urutan aslinya (karena Anda tidak menyimpan informasi pemesanan)
Atau, Anda bisa mengonversi daftar Anda ke @Transient dan menambahkan bidang lain (argStorage) ke kelas Anda yang merupakan VARCHAR () atau CLOB. Anda kemudian perlu menambahkan 3 fungsi: 2 di antaranya adalah sama dan harus mengubah daftar Strings Anda menjadi satu String (dalam argStorage) dibatasi dengan cara yang Anda dapat dengan mudah memisahkannya. Beri catatan dua fungsi ini (yang masing-masing melakukan hal yang sama) dengan @PrePersist dan @PreUpdate. Terakhir, tambahkan fungsi ketiga yang membagi argStorage ke dalam daftar Strings lagi dan beri catatan @PostLoad. Ini akan membuat CLOB Anda diperbarui dengan string kapan pun Anda pergi untuk menyimpan Perintah, dan menjaga bidang argStorage diperbarui sebelum Anda menyimpannya ke DB.
Saya masih menyarankan melakukan kasus pertama. Ini praktik yang baik untuk hubungan yang nyata nanti.
sumber
Menurut Java Persistence with Hibernate
Jika Anda menggunakan Hibernate, Anda bisa melakukan sesuatu seperti:
Pembaruan: Catatan, ini sekarang tersedia di JPA2.
sumber
Kita juga bisa menggunakan ini.
sumber
Saya memiliki masalah yang sama sehingga saya menginvestasikan solusi yang mungkin diberikan tetapi pada akhirnya saya memutuskan untuk menerapkan ';' daftar String yang terpisah.
jadi saya punya
Dengan cara ini daftar ini mudah dibaca / diedit dalam tabel database;
sumber
arguments
adalah daftar izin akses, maka memiliki karakter khusus, aseparator
, mungkin rentan terhadap serangan eskalasi hak istimewa.;
yang akan merusak aplikasi Anda.Saat menggunakan implementasi Hibernate JPA, saya telah menemukan bahwa dengan mendeklarasikan tipe sebagai ArrayList, bukan List, memungkinkan hibernate untuk menyimpan daftar data.
Jelas ini memiliki sejumlah kelemahan dibandingkan dengan membuat daftar objek Entitas. Tidak ada pemuatan malas, tidak ada kemampuan untuk referensi entitas dalam daftar dari objek lain, mungkin lebih sulit dalam membangun query database. Namun ketika Anda berhadapan dengan daftar jenis yang cukup primitif yang Anda selalu ingin bersemangat untuk mengambil bersama dengan entitas, maka pendekatan ini tampaknya baik untuk saya.
sumber
@OneToMany
@ManyToOne
@ElementCollection
itu akan memberi AndaCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
pengecualian pada startup server. Karena hibernasi ingin Anda menggunakan antarmuka koleksi.Tampaknya tidak ada jawaban yang mengeksplorasi pengaturan paling penting untuk
@ElementCollection
pemetaan.Saat Anda memetakan daftar dengan anotasi ini, dan biarkan JPA / Hibernate otomatis membuat tabel, kolom, dll., Ia juga akan menggunakan nama yang dihasilkan secara otomatis.
Jadi, mari kita menganalisis contoh dasar:
@ElementCollection
Anotasi dasar (di mana Anda dapat menentukan yang diketahuifetch
dantargetClass
preferensi)@CollectionTable
penjelasan ini sangat berguna ketika datang untuk memberikan nama untuk tabel yang akan dihasilkan, serta definisi sepertijoinColumns
,foreignKey
's,indexes
,uniqueConstraints
, dll@Column
Penting untuk menentukan nama kolom yang akan menyimpanvarchar
nilai daftar.Pembuatan DDL yang dihasilkan adalah:
sumber
Ok saya tahu agak terlambat. Tetapi bagi jiwa-jiwa pemberani yang akan melihat ini seiring berjalannya waktu.
Seperti yang tertulis dalam dokumentasi :
Bagian yang penting adalah tipe yang mengimplementasikan Serializable
Jadi sejauh ini solusi yang paling sederhana dan termudah untuk digunakan adalah hanya menggunakan ArrayList, bukan List (atau wadah serializable):
Namun perlu diingat bahwa ini akan menggunakan sistem serialisasi, sehingga akan datang dengan beberapa harga, seperti:
jika model objek serial akan berubah, Anda mungkin tidak dapat mengembalikan data
overhead kecil ditambahkan untuk setiap elemen yang disimpan.
Pendeknya
cukup sederhana untuk menyimpan flag atau beberapa elemen, tetapi saya tidak akan merekomendasikannya untuk menyimpan data yang mungkin bertambah besar.
sumber
Jawaban thiago benar, menambahkan sampel yang lebih spesifik untuk pertanyaan, @ElementCollection akan membuat tabel baru di database Anda, tetapi tanpa memetakan dua tabel, itu berarti bahwa koleksi tersebut bukan kumpulan entitas, tetapi kumpulan tipe sederhana (String, dll. .) atau kumpulan elemen yang dapat di- embed (kelas dijelaskan dengan @Embeddable ).
Berikut adalah contoh untuk mempertahankan daftar String
Ini adalah contoh untuk melanjutkan daftar objek Kustom
Untuk hal ini kita perlu membuat kelas Embeddable
sumber
Ini adalah solusi untuk menyimpan Set menggunakan @Converter dan StringTokenizer. Pemeriksaan lebih sedikit terhadap solusi @ jonck-van-der-kogel .
Di kelas Entity Anda:
StringSetConverter:
sumber
Perbaikan saya untuk masalah ini adalah memisahkan kunci utama dengan kunci asing. Jika Anda menggunakan eclipse dan melakukan perubahan di atas, harap ingat untuk menyegarkan basis data explorer. Kemudian buat kembali entitas dari tabel.
sumber