Was ist der intelligenteste Weg, um eine Entität mit einem Feld vom Typ Liste dauerhaft zu erhalten?
Command.java
package persistlistofstring;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Basic
List<String> arguments = new ArrayList<String>();
public static void main(String[] args) {
Command command = new Command();
EntityManager em = Persistence
.createEntityManagerFactory("pu")
.createEntityManager();
em.getTransaction().begin();
em.persist(command);
em.getTransaction().commit();
em.close();
System.out.println("Persisted with id=" + command.id);
}
}
Dieser Code erzeugt:
> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack:
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
> at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
> at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
> at persistlistofstring.Command.main(Command.java:30)
> Caused by:
> ...
Es tut mir leid, einen alten Thread wiederzubeleben, aber sollte jemand nach einer alternativen Lösung suchen, bei der Sie Ihre Zeichenfolgenlisten als ein Feld in Ihrer Datenbank speichern, habe ich das folgendermaßen gelöst. Erstellen Sie einen Konverter wie folgt:
Verwenden Sie es jetzt wie folgt für Ihre Entitäten:
In der Datenbank wird Ihre Liste als foo; bar; foobar gespeichert und in Ihrem Java-Objekt erhalten Sie eine Liste mit diesen Zeichenfolgen.
Hoffe das ist hilfreich für jemanden.
quelle
SPLIT_CHAR
Ihre Zeichenfolge keine Vorkommen enthalten kann.Diese Antwort wurde vor JPA2-Implementierungen gegeben. Wenn Sie JPA2 verwenden, lesen Sie die Antwort von ElementCollection oben:
Listen von Objekten innerhalb eines Modellobjekts werden im Allgemeinen als "OneToMany" -Beziehungen zu einem anderen Objekt betrachtet. Ein String ist jedoch (für sich genommen) kein zulässiger Client einer Eins-zu-Viele-Beziehung, da er keine ID hat.
Also, Sie sollten Ihre Liste von Strings auf eine Liste von Argument-Klasse JPA konvertieren Objekte enthält eine ID und ein String. Sie könnten möglicherweise den String als ID verwenden, wodurch ein wenig Platz in Ihrer Tabelle gespart wird, sowohl durch Entfernen des ID-Felds als auch durch Konsolidieren von Zeilen, in denen die Strings gleich sind. Sie würden jedoch die Möglichkeit verlieren, die Argumente wieder in ihre ursprüngliche Reihenfolge zu bringen (da Sie keine Bestellinformationen gespeichert haben).
Alternativ können Sie Ihre Liste in @Transient konvertieren und Ihrer Klasse ein weiteres Feld (argStorage) hinzufügen, das entweder ein VARCHAR () oder ein CLOB ist. Sie müssen dann 3 Funktionen hinzufügen: 2 davon sind identisch und sollten Ihre Liste der Zeichenfolgen in eine einzelne Zeichenfolge (in argStorage) konvertieren, die so abgegrenzt ist, dass Sie sie leicht trennen können. Kommentieren Sie diese beiden Funktionen (die jeweils dasselbe tun) mit @PrePersist und @PreUpdate. Fügen Sie abschließend die dritte Funktion hinzu, mit der argStorage erneut in die Liste der Zeichenfolgen aufgeteilt wird, und kommentieren Sie sie mit @PostLoad. Dadurch wird Ihr CLOB immer mit den Zeichenfolgen aktualisiert, wenn Sie den Befehl speichern, und das Feld argStorage wird aktualisiert, bevor Sie es in der Datenbank speichern.
Ich schlage immer noch vor, den ersten Fall zu machen. Es ist eine gute Praxis für echte Beziehungen später.
quelle
Laut Java Persistence with Hibernate
Wenn Sie den Ruhezustand verwenden, können Sie Folgendes tun:
Update: Beachten Sie, dass dies jetzt in JPA2 verfügbar ist.
quelle
Wir können dies auch nutzen.
quelle
Bei der Verwendung der JPA-Implementierung im Ruhezustand habe ich festgestellt, dass durch einfaches Deklarieren des Typs als ArrayList anstelle von List die Liste der Daten im Ruhezustand gespeichert werden kann.
Dies hat eindeutig eine Reihe von Nachteilen gegenüber dem Erstellen einer Liste von Entitätsobjekten. Kein verzögertes Laden, keine Möglichkeit, die Entitäten in der Liste von anderen Objekten aus zu referenzieren, möglicherweise größere Schwierigkeiten beim Erstellen von Datenbankabfragen. Wenn Sie sich jedoch mit Listen ziemlich primitiver Typen befassen, die Sie immer eifrig zusammen mit der Entität abrufen möchten, scheint mir dieser Ansatz in Ordnung zu sein.
quelle
@OneToMany
@ManyToOne
@ElementCollection
damit versuchen , erhalten SieCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
beim Serverstart eine Ausnahme. Weil der Ruhezustand möchte, dass Sie Erfassungsschnittstellen verwenden.Ich hatte das gleiche Problem, also habe ich die mögliche Lösung investiert, aber am Ende habe ich beschlossen, mein ';' getrennte Liste von String.
Also habe ich
Auf diese Weise ist die Liste in der Datenbanktabelle leicht lesbar / bearbeitbar.
quelle
arguments
eine Liste von Zugriffsberechtigungen ist, kann ein Sonderzeichen aseparator
für Angriffe zur Eskalation von Berechtigungen anfällig sein.;
die Ihre App beschädigen.Es scheint, dass keine der Antworten die wichtigsten Einstellungen für ein
@ElementCollection
Mapping untersucht hat.Wenn Sie eine Liste mit dieser Anmerkung zuordnen und JPA / Hibernate die Tabellen, Spalten usw. automatisch generieren lässt, werden auch automatisch generierte Namen verwendet.
Analysieren wir also ein grundlegendes Beispiel:
@ElementCollection
Anmerkung (wo Sie die bekanntenfetch
undtargetClass
Einstellungen definieren können )@CollectionTable
Anmerkung ist sehr nützlich , wenn es einen Namen für die Tabelle geben kommt , die erzeugt werden , werden, sowie Definitionen wiejoinColumns
,foreignKey
‚s,indexes
,uniqueConstraints
etc.@Column
Es ist wichtig, den Namen der Spalte zu definieren, in der dervarchar
Wert der Liste gespeichert wird .Die generierte DDL-Erstellung wäre:
quelle
Ok, ich weiß, dass es etwas spät ist. Aber für jene tapferen Seelen, die dies im Laufe der Zeit sehen werden.
Wie in der Dokumentation geschrieben :
Der wichtige Teil ist der Typ, der Serializable implementiert
Die mit Abstand einfachste und am einfachsten zu verwendende Lösung ist die Verwendung von ArrayList anstelle von List (oder eines beliebigen serialisierbaren Containers):
Denken Sie jedoch daran, dass hierfür die System-Serialisierung verwendet wird, sodass ein gewisser Preis anfällt, z.
Wenn sich das serialisierte Objektmodell ändert, können Sie möglicherweise keine Daten wiederherstellen
Für jedes gespeicherte Element wird ein geringer Overhead hinzugefügt.
Zusamenfassend
Es ist ganz einfach, Flags oder wenige Elemente zu speichern, aber ich würde es nicht empfehlen, Daten zu speichern, die groß werden könnten.
quelle
Diese Antwort ist richtig. Wenn Sie ein Beispiel hinzufügen, das spezifischer für die Frage ist, erstellt @ElementCollection eine neue Tabelle in Ihrer Datenbank, ohne jedoch zwei Tabellen zuzuordnen. Dies bedeutet, dass die Sammlung keine Sammlung von Entitäten ist, sondern eine Sammlung einfacher Typen (Strings usw.) .) oder eine Sammlung einbettbarer Elemente (mit @Embeddable kommentierte Klasse ).
Hier ist das Beispiel, um die Liste der Zeichenfolgen beizubehalten
Hier ist das Beispiel, um die Liste der benutzerdefinierten Objekte beizubehalten
Für diesen Fall müssen wir die Klasse Embeddable machen
quelle
Hier ist die Lösung zum Speichern eines Sets mit @Converter und StringTokenizer. Ein bisschen mehr Überprüfungen gegen @ jonck-van-der-kogel- Lösung.
In Ihrer Entitätsklasse:
StringSetConverter:
quelle
Meine Lösung für dieses Problem bestand darin, den Primärschlüssel vom Fremdschlüssel zu trennen. Wenn Sie Eclipse verwenden und die oben genannten Änderungen vorgenommen haben, müssen Sie den Datenbank-Explorer aktualisieren. Erstellen Sie dann die Entitäten aus den Tabellen neu.
quelle