JPA-Mapping Multi-Zeilen mit ElementCollection
Ich versuche zu Folgen, die JPA tutorial und mit ElementCollection
aufzunehmen Mitarbeiter Telefon-Nummern:
PHONE (table)
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
Kurze version
Was ich brauche, ist eine Klasse wie folgt aus:
@Entity
@Table(name="Phones")
public class PhoneId {
@Id
@Column(name="owner_id")
long owner_id;
@Embedded
List<Phone> phones;
}
speichert jede person, die Telefonnummern in einer Sammlung.
Lange version
Folge ich den tutorial-code:
@Entity
@Table(name="Phones")
public class PhoneId {
@Id
@Column(name="owner_id")
long owner_id;
@ElementCollection
@CollectionTable(
name="Phones",
joinColumns=@JoinColumn(name="owner_id")
)
List<Phone> phones = new ArrayList<Phone>();
}
@Embeddable
class Phone {
@Column(name="type")
String type = "";
@Column(name="number")
String number = "";
public Phone () {}
public Phone (String type, String number)
{ this.type = type; this.number = number; }
}
mit einem kleinen Unterschied, dass ich immer nur eine Tabelle. Ich habe versucht, verwenden Sie den folgenden code hinzu, um Datensätze zu dieser Tabelle:
public static void main (String[] args) {
EntityManagerFactory entityFactory =
Persistence.createEntityManagerFactory("Tutorial");
EntityManager entityManager = entityFactory.createEntityManager();
//Create new entity
entityManager.getTransaction().begin();
Phone ph = new Phone("home", "001-010-0100");
PhoneId phid = new PhoneId();
phid.phones.add(ph);
entityManager.persist(phid);
entityManager.getTransaction().commit();
entityManager.close();
}
aber es hält werfen von Ausnahmen
Internal Exception: org.postgresql.util.PSQLException: FEHLER: null
Wert in der Spalte "Typ" verletzt not-null-Einschränkung Detail: Versagt
Zeile enthält (0, null, null). Error Code: 0 Aufruf: INSERT INTO Telefone
(owner_id) VALUES (?) binden => [1 parameter gebunden] Query:
InsertObjectQuery(tutorial.Phone1@162e295)
Was habe ich falsch gemacht?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Traurig, ich denke dem kleinen Unterschied, dass Sie immer nur eine Tabelle ist hier das problem.
Blick auf die Erklärung des
PhoneId
Klasse (was ich vorschlagen würde ist eher alsPhoneOwner
oder so ähnlich):Wenn Sie erklären, dass Sie eine Klasse ist eine Einheit zugeordnet, um eine bestimmte Tabelle, die Sie machen eine Reihe von Behauptungen, von denen zwei besonders wichtig sind hier. Erstens, dass es eine Zeile in der Tabelle für jede Instanz der Entität, und Umgekehrt. Zweitens, dass es eine Spalte in der Tabelle für jedes Skalare Feld des Unternehmens, und vice versa. Diese beiden sind das Herz von der Idee des Objekt-relationalen mapping.
Jedoch, in Ihrem schema, weder von diesen Behauptungen halten. In die Daten, die Sie gab:
Gibt es zwei Zeilen, entsprechend der Einheit, die mit
owner_id
1, gegen die erste Behauptung. Es gibt SpaltenTYPE
undNUMBER
die nicht zugeordneten Felder in der Entität, die gegen die zweite Behauptung.(Klar, es ist nichts falsch mit Ihrer Erklärung der
Phone
Klasse oder diephones
Feld - nur diePhoneId
Person)Als Ergebnis, wenn Sie Ihre JPA-provider versucht, legen Sie eine Instanz von
PhoneId
in die Datenbank, läuft es in Schwierigkeiten. Da gibt es keine Zuordnungen für dieTYPE
undNUMBER
Spalten inPhoneId
, wenn er generiert den SQL-Code für die insert -, es zählen nicht die Werte für Sie. Dies ist, warum Sie erhalten die Fehlermeldung, die Sie sehen - der Anbieter schreibtINSERT INTO Phones (owner_id) VALUES (?)
, die PostgreSQL behandelt, alsINSERT INTO Phones (owner_id, type, number) VALUES (?, null, null)
, die abgelehnt wird.Selbst wenn Sie es verwalten einfügen einer Zeile in dieser Tabelle würde dann in Schwierigkeiten geraten, die auf das abrufen von einem Objekt aus. Sagen Sie aufgefordert, die Instanz von
PhoneId
mitowner_id
1. Der Anbieter schreiben würde, SQL in Höhe vonselect * from Phones where owner_id = 1
, und es wäre zu erwarten, dass zu finden, die genau eine Zeile, das kann eine Zuordnung zu einem Objekt. Aber es finden zwei Zeilen!Die Lösung, die ich fürchte, ist die Verwendung von zwei Tabellen, eine für
PhoneId
, und eine fürPhone
. Die Tabelle fürPhoneId
wird trivial einfach, aber es ist notwendig für den korrekten Betrieb des JPA Maschinen.Vorausgesetzt, Sie umbenennen
PhoneId
zuPhoneOwner
, die Tabellen müssen so Aussehen:(Ich habe
(owner_id, number)
den Primärschlüssel fürPhone
auf der Annahme, dass ein Eigentümer möglicherweise mehr als eine Reihe von einem bestimmten Typ, aber nie einen Nummer erfasst unter zwei Arten. Sie könnten es vorziehen(owner_id, type)
wenn, die besser widerspiegelt Ihre domain.)Entitäten sind dann:
Nun, wenn Sie wirklich nicht wollen, um einzuführen, eine Tabelle für die
PhoneOwner
sind, dann könnten Sie in der Lage sein, um aus der es mit einem Blick. Wie diese:So weit als JPA-provider kann sagen, dies ist eine Tabelle, und es wird Unterstützung für die Abfragen, die er tun muss, um Daten zu Lesen.
Jedoch, es wird nicht die Unterstützung der Einsätze. Wenn Sie sich jemals gewünscht, um ein Telefon hinzufügen für einen Eigentümer, die derzeit nicht in der Datenbank, würden Sie brauchen, um zu gehen um die Rückseite und eine Zeile einfügen, direkt in
Phone
. Nicht sehr nett.@Embeddable
konnte verhindern, dass Klassen interpretiert wird als Tabellen. Könnten wir machenPhoneOwner
@Embeddable
,Phone
@Entity
, und dieList
@Transient
? Ich sah gerade diesen Vorschlag auf stackoverflow.com/questions/9318387/....Phone
Entität, und dann gruppieren Sie Sie durch die Eigentümer, die Schaffung von etwas rein in-memory -PhoneOwner
Objekte, nachdem Sie Sie geladen haben.type
, hat Ihre Lösung noch arbeiten? Mein eigentliches problem ist eigentlich komplizierter als das, und ich bin derzeit mit Vererbung, sondern aus dem JPA wikibook-Vererbung wird nicht unterstützt für embeddables.Phone
eine Einheit. Sie können dann entwederPhoneOwner
werden, eine Entität mit einer separaten Tabelle, und eine@OneToMany
Beziehung zuPhone
oder haben Sie ein nicht-persistentes Objekt, und führen Sie die Gruppierung im code.