sql >> Database teknologi >  >> RDS >> PostgreSQL

JPA-kortlægning af flere rækker med ElementCollection

Desværre tror jeg, at den lille forskel, at du kun beholder ét bord, er problemet her.

Se på erklæringen om PhoneId klasse (som jeg vil foreslå bedre kaldes PhoneOwner eller sådan noget):

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

Når du erklærer, at en klasse er en entitet, der er knyttet til en bestemt tabel, fremsætter du et sæt påstande, hvoraf to er særligt vigtige her. For det første, at der er én række i tabellen for hver forekomst af entiteten og omvendt. For det andet, at der er én kolonne i tabellen for hvert skalarfelt i entiteten og omvendt. Begge disse er kernen i ideen om objektrelationel kortlægning.

Men i dit skema holder ingen af ​​disse påstande. I de data, du har givet:

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

Der er to rækker, der svarer til enheden med owner_id 1, i strid med den første påstand. Der er kolonner TYPE og NUMBER som ikke er knyttet til felter i entiteten, hvilket overtræder den anden påstand.

(For at være klar, er der intet galt med din erklæring om Phone klasse eller phones felt - kun PhoneId enhed)

Som et resultat, når din JPA-udbyder forsøger at indsætte en forekomst af PhoneId ind i databasen, løber den ind i problemer. Fordi der ikke er nogen tilknytninger til TYPE og NUMBER kolonner i PhoneId , når den genererer SQL'en for indsættelsen, inkluderer den ikke værdier for dem. Det er derfor, du får den fejl, du ser - udbyderen skriver INSERT INTO Phones (owner_id) VALUES (?) , som PostgreSQL behandler som INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null) , hvilket afvises.

Selvom det lykkedes dig at indsætte en række i denne tabel, ville du løbe ind i problemer med at hente et objekt fra den. Lad os sige, at du bad om forekomsten af ​​PhoneId med owner_id 1. Udbyderen ville skrive SQL svarende til select * from Phones where owner_id = 1 , og den ville forvente, at den finder præcis én række, som den kan kortlægge til et objekt. Men den finder to rækker!

Løsningen er, er jeg bange for, at bruge to tabeller, en for PhoneId , og en for Phone . Tabellen for PhoneId vil være trivielt simpelt, men det er nødvendigt for korrekt drift af JPA-maskineriet.

Forudsat at du omdøber PhoneId til PhoneOwner , skal tabellerne se sådan ud:

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

(Jeg har lavet (owner_id, number) den primære nøgle til Phone , ud fra den antagelse, at en ejer kan have mere end ét nummer af en given type, men aldrig vil have ét nummer registreret under to typer. Du foretrækker måske (owner_id, type) hvis det bedre afspejler dit domæne.)

Entiteterne er så:

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

Nu, hvis du virkelig ikke ønsker at introducere en tabel for PhoneOwner , så kan du måske komme ud af det ved hjælp af en udsigt. Sådan:

create view PhoneOwner as select distinct owner_id from Phone;

Så vidt JPA-udbyderen kan se, er dette en tabel, og den understøtter de forespørgsler, den skal udføre for at læse data.

Den understøtter dog ikke indsatser. Hvis du nogensinde har haft brug for at tilføje en telefon til en ejer, der ikke er i databasen i øjeblikket, skal du gå bagud og indsætte en række direkte i Phone . Ikke særlig rart.




  1. Indsættelse af datoværdi i MySQL gennem PHP

  2. nulstil root-adgangskoden med forkert mysql-konfiguration

  3. Broken Pipe Exception on Grails App

  4. Postgres-kodning UTF8-fejl under indsættelse af billeder via Java