sql >> Database >  >> RDS >> PostgreSQL

JPA Mapping Multi-Rows met ElementCollection

Helaas denk ik dat het kleine verschil dat je maar één tafel aanhoudt hier het probleem is.

Kijk naar de aangifte van de PhoneId klasse (die ik zou aanraden beter PhoneOwner te noemen) of iets dergelijks):

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

Wanneer u verklaart dat een klasse een entiteit is die is toegewezen aan een bepaalde tabel, maakt u een reeks beweringen, waarvan er twee hier bijzonder belangrijk zijn. Ten eerste dat er één rij in de tabel is voor elke instantie van de entiteit, en vice versa. Ten tweede dat er één kolom in de tabel is voor elk scalair veld van de entiteit, en vice versa. Beide vormen de kern van het idee van object-relationele mapping.

In uw schema gaat geen van beide beweringen echter op. In de gegevens die je hebt gegeven:

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

Er zijn twee rijen die overeenkomen met de entiteit met owner_id 1, in strijd met de eerste bewering. Er zijn kolommen TYPE en NUMBER die niet zijn toegewezen aan velden in de entiteit, in strijd met de tweede bewering.

(Voor alle duidelijkheid, er is niets mis met uw aangifte van de Phone klas of de phones veld - alleen de PhoneId entiteit)

Als gevolg hiervan, wanneer uw JPA-provider probeert een instantie van PhoneId in te voegen, in de database, komt het in de problemen. Omdat er geen toewijzingen zijn voor het TYPE en NUMBER kolommen in PhoneId , wanneer het de SQL voor de insert genereert, bevat het geen waarden voor hen. Dit is waarom je de foutmelding krijgt die je ziet - de provider schrijft INSERT INTO Phones (owner_id) VALUES (?) , die PostgreSQL behandelt als INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null) , die wordt afgewezen.

Zelfs als het je zou lukken om een ​​rij in deze tabel in te voegen, zou je problemen krijgen bij het ophalen van een object uit de tabel. Stel dat u hebt gevraagd om de instantie van PhoneId met owner_id 1. De provider zou SQL schrijven voor een bedrag van select * from Phones where owner_id = 1 , en het zou verwachten dat het precies één rij zou vinden, die het kan toewijzen aan een object. Maar het zal twee rijen vinden!

De oplossing is, vrees ik, om twee tabellen te gebruiken, één voor PhoneId , en één voor Phone . De tabel voor PhoneId zal triviaal eenvoudig zijn, maar het is noodzakelijk voor de juiste werking van de JPA-machinerie.

Ervan uitgaande dat u de naam PhoneId hernoemt naar PhoneOwner , moeten de tabellen er als volgt uitzien:

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

(Ik heb (owner_id, number) gemaakt de primaire sleutel voor Phone , in de veronderstelling dat één eigenaar meer dan één nummer van een bepaald type kan hebben, maar nooit één nummer zal hebben geregistreerd onder twee typen. Misschien geeft u de voorkeur aan (owner_id, type) als dat beter aansluit bij uw domein.)

De entiteiten zijn dan:

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

Als u nu echt geen tabel wilt introduceren voor de PhoneOwner , dan kun je er misschien uit komen met een weergave. Zoals dit:

create view PhoneOwner as select distinct owner_id from Phone;

Voor zover de PPV-provider kan zien, is dit een tabel en ondersteunt deze de query's die nodig zijn om gegevens te lezen.

Het ondersteunt echter geen inserts. Als u ooit een telefoon moest toevoegen voor een eigenaar die momenteel niet in de database staat, moet u helemaal naar achteren gaan en direct een rij invoegen in Phone . Niet erg aardig.




  1. Hoe maak ik een MySQL-verbindingspool terwijl ik met NodeJS en Express werk?

  2. Grote prestatieproblemen met Oracle DataReader in .Net

  3. MySQL selecteren voor na rij

  4. Een array maken van een MySQL-tabel