PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

JPA картографиране на няколко реда с ElementCollection

За съжаление мисля, че малката разлика, че поддържате само една таблица, е проблемът тук.

Вижте декларацията на PhoneId клас (който бих предложил да се нарича по-добре PhoneOwner или нещо подобно):

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

Когато декларирате, че даден клас е обект, картографиран към определена таблица, вие правите набор от твърдения, две от които са особено важни тук. Първо, че има един ред в таблицата за всеки екземпляр на обекта и обратно. Второ, че има една колона в таблицата за всяко скаларно поле на обекта и обратно. И двете са в основата на идеята за обектно-релационно картографиране.

Във вашата схема обаче нито едно от тези твърдения не е валидно. В предоставените от вас данни:

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

Има два реда, съответстващи на обекта с owner_id 1, нарушавайки първото твърдение. Има колони TYPE и NUMBER които не са съпоставени с полета в обекта, нарушавайки второто твърдение.

(За да бъде ясно, няма нищо лошо в декларацията ви за Phone клас или phones поле - само PhoneId обект)

В резултат на това, когато вашият JPA доставчик се опита да вмъкне екземпляр на PhoneId в базата данни, се натъква на проблеми. Тъй като няма съпоставяния за TYPE и NUMBER колони в PhoneId , когато генерира SQL за вмъкване, той не включва стойности за тях. Ето защо получавате грешката, която виждате - доставчикът пише INSERT INTO Phones (owner_id) VALUES (?) , което PostgreSQL третира като INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null) , което е отхвърлено.

Дори и да сте успели да вмъкнете ред в тази таблица, ще имате проблеми при извличането на обект от нея. Да кажем, че сте поискали екземпляра на PhoneId с owner_id 1. Доставчикът ще напише SQL в размер на select * from Phones where owner_id = 1 , и би очаквало, че ще намери точно един ред, който може да картографира към обект. Но ще намери два реда!

Опасявам се, че решението е да се използват две таблици, едната за PhoneId и един за Phone . Таблицата за PhoneId ще бъде тривиално просто, но е необходимо за правилното функциониране на машината на JPA.

Ако приемем, че преименувате PhoneId до PhoneOwner , таблиците трябва да изглеждат така:

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)
)

(Направих (owner_id, number) първичен ключ за Phone , при допускането, че един собственик може да има повече от един номер от даден тип, но никога няма да има един номер, записан под два типа. Може да предпочетете (owner_id, type) ако това отразява по-добре вашия домейн.)

Тогава обектите са:

@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;
}

Сега, ако наистина не искате да въведете таблица за PhoneOwner , тогава може да успеете да излезете от него с помощта на изглед. Като това:

create view PhoneOwner as select distinct owner_id from Phone;

Доколкото може да разбере доставчикът на JPA, това е таблица и ще поддържа заявките, които трябва да направи, за да прочете данни.

Той обаче няма да поддържа вмъквания. Ако някога ви се наложи да добавите телефон за собственик, който в момента не е в базата данни, ще трябва да отидете отзад и да вмъкнете ред директно в Phone . Не е много хубаво.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Функция като параметър към друга функция в Postgres

  2. ГРЕШКА:кешираният план не трябва да променя типа резултат при смесване на DDL с SELECT чрез JDBC

  3. Синхронизиране на elasticsearch при връзка с база данни - nodeJS

  4. pgAdmin алтернативи - PostgreSQL управление на база данни GUI ClusterControl

  5. Какъв е най-бързият начин да направите групово вмъкване в Postgres?