PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Pemetaan JPA Multi-Baris dengan ElementCollection

Sayangnya, saya pikir sedikit perbedaan bahwa Anda hanya menyimpan satu meja adalah masalahnya di sini.

Lihat deklarasi PhoneId kelas (yang saya sarankan lebih baik disebut PhoneOwner atau semacamnya):

@Entity
@Table(name="Phones")
public class PhoneId {

Saat Anda mendeklarasikan bahwa kelas adalah entitas yang dipetakan ke tabel tertentu, Anda membuat serangkaian pernyataan, di mana dua di antaranya sangat penting di sini. Pertama, ada satu baris dalam tabel untuk setiap instance entitas, dan sebaliknya. Kedua, bahwa ada satu kolom dalam tabel untuk setiap bidang skalar entitas, dan sebaliknya. Keduanya merupakan inti dari ide pemetaan relasional objek.

Namun, dalam skema Anda, tidak satu pun dari pernyataan ini berlaku. Dalam data yang Anda berikan:

OWNER_ID    TYPE      NUMBER
  1         home      792-0001
  1         work      494-1234
  2         work      892-0005

Ada dua baris yang sesuai dengan entitas dengan owner_id 1, melanggar pernyataan pertama. Ada kolom TYPE dan NUMBER yang tidak dipetakan ke bidang dalam entitas, melanggar pernyataan kedua.

(Agar jelas, tidak ada yang salah dengan pernyataan Anda tentang Phone kelas atau phones bidang - cukup PhoneId entitas)

Akibatnya, ketika penyedia JPA Anda mencoba memasukkan instance PhoneId ke dalam database, itu mengalami masalah. Karena tidak ada pemetaan untuk TYPE dan NUMBER kolom di PhoneId , ketika menghasilkan SQL untuk sisipan, itu tidak menyertakan nilai untuk mereka. Inilah sebabnya mengapa Anda mendapatkan kesalahan yang Anda lihat - penyedia menulis INSERT INTO Phones (owner_id) VALUES (?) , yang diperlakukan PostgreSQL sebagai INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null) , yang ditolak.

Bahkan jika Anda berhasil memasukkan baris ke dalam tabel ini, Anda akan mengalami masalah saat mengambil objek darinya. Katakanlah Anda meminta contoh PhoneId dengan owner_id 1. Penyedia akan menulis SQL sebesar select * from Phones where owner_id = 1 , dan diharapkan untuk menemukan tepat satu baris, yang dapat dipetakan ke suatu objek. Tapi itu akan menemukan dua baris!

Solusinya, saya khawatir, adalah menggunakan dua tabel, satu untuk PhoneId , dan satu untuk Phone . Tabel untuk PhoneId akan sangat sederhana, tetapi perlu untuk pengoperasian mesin JPA yang benar.

Dengan asumsi Anda mengganti nama PhoneId ke PhoneOwner , tabel harus terlihat seperti:

create table PhoneOwner (
    owner_id integer primary key
)

create table Phone (
    owner_id integer not null references PhoneOwner,
    type varchar(255) not null,
    number varchar(255) not null,
    primary key (owner_id, number)
)

(Saya sudah membuat (owner_id, number) kunci utama untuk Phone , dengan asumsi bahwa satu pemilik mungkin memiliki lebih dari satu nomor dari jenis tertentu, tetapi tidak akan pernah memiliki satu nomor yang tercatat di bawah dua jenis. Anda mungkin lebih suka (owner_id, type) jika itu mencerminkan domain Anda dengan lebih baik.)

Entitasnya adalah:

@Entity
@Table(name="PhoneOwner")
public class PhoneOwner {
    @Id
    @Column(name="owner_id")
    long id;

    @ElementCollection
    @CollectionTable(name = "Phone", joinColumns = @JoinColumn(name = "owner_id"))
    List<Phone> phones = new ArrayList<Phone>();
}

@Embeddable
class Phone {
    @Column(name="type", nullable = false)
    String type;
    @Column(name="number", nullable = false)
    String number;
}

Sekarang, jika Anda benar-benar tidak ingin memperkenalkan tabel untuk PhoneOwner , maka Anda mungkin bisa keluar darinya menggunakan tampilan. Seperti ini:

create view PhoneOwner as select distinct owner_id from Phone;

Sejauh yang diketahui oleh penyedia JPA, ini adalah tabel, dan akan mendukung kueri yang perlu dilakukan untuk membaca data.

Namun, itu tidak akan mendukung sisipan. Jika Anda perlu menambahkan telepon untuk pemilik yang saat ini tidak ada dalam database, Anda harus memutar ke belakang dan menyisipkan baris langsung ke Phone . Tidak terlalu bagus.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menghapus duplikat sehingga hanya pasangan yang ada di tabel?

  2. Verifikasi koneksi database dengan pg-promise saat memulai aplikasi

  3. Cara Memantau Kinerja PostgreSQL 12 dengan OmniDB – Bagian 1

  4. Cegah pemicu rekursif di PostgreSQL

  5. Bagaimana cara mengubah ID tabel dari serial menjadi identitas?