Hibernate – @ElementCollection – Seltsames Verhalten beim Löschen/Einfügen

Lesezeit: 7 Minuten

Hibernate @ElementCollection Seltsames Verhalten beim LoschenEinfugen
Nihilist84

@Entity
public class Person {

    @ElementCollection
    @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
    private List<Location> locations;

    [...]

}

@Embeddable
public class Location {

    [...]

}

Wenn ich bei der folgenden Klassenstruktur versuche, einen neuen Standort zur Liste der Standorte von Personen hinzuzufügen, führt dies immer zu den folgenden SQL-Abfragen:

DELETE FROM PERSON_LOCATIONS WHERE PERSON_ID = :idOfPerson

Und

A lotsa' inserts into the PERSON_LOCATIONS table

Hibernate (3.5.x / JPA 2) löscht alle zugehörigen Datensätze für die angegebene Person und fügt alle vorherigen Datensätze sowie den neuen erneut ein.

Ich hatte die Idee, dass die equals/hashcode-Methode auf Location das Problem lösen würde, aber es hat nichts geändert.

Alle Hinweise sind willkommen!

  • Ich hatte das gegenteilige Problem – Hibernate löschte nichts, als ich das übergeordnete Element aktualisierte. Dies war der einzige diesbezügliche Beitrag, den ich im Netz gefunden habe, einschließlich der Hibernate-Dokumentation bei JBoss. Es stellt sich aus jetzt unbekannten Gründen heraus, dass ich die Sammlungsvariable auf dem übergeordneten Element als deklariert hatte final und Hibernate hat stillschweigend nichts getan. Ich habe die herausgenommen final und es fing an, gut zu aktualisieren und zu löschen.

    – Adam

    28. September 2015 um 13:42 Uhr

  • Ich habe festgestellt, dass dies mit passiert fetch = FetchType.EAGER auch auf einfache Listenoperationen (nicht aktualisieren oder löschen)l. @OrderColumn scheint keine Wirkung zu haben

    – Lichtschalter05

    1. Mai 2017 um 23:26 Uhr

Hibernate @ElementCollection Seltsames Verhalten beim LoschenEinfugen
Pascal Thivent

Das Problem wird irgendwie auf der Seite über erklärt ElementCollection des JPA-Wikibooks:

Primärschlüssel in CollectionTable

Die JPA 2.0-Spezifikation bietet keine Möglichkeit, die Id in dem
Embeddable. Um jedoch ein Element der zu löschen oder zu aktualisieren
ElementCollection Mapping, ist normalerweise ein eindeutiger Schlüssel erforderlich. Andernfalls müsste der JPA-Anbieter bei jedem Update alles aus der löschen
CollectionTable für die Entityund fügen Sie dann die Werte wieder ein.
Daher wird der JPA-Anbieter höchstwahrscheinlich davon ausgehen, dass die Kombination aller Felder in der Embeddable sind eindeutig, in Kombination mit dem Fremdschlüssel (JoinColunm(S)). Dies könnte jedoch ineffizient oder einfach nicht durchführbar sein, wenn dies der Fall ist Embeddable ist groß oder komplex.

Und genau das (der fettgedruckte Teil) passiert hier (Hibernate generiert keinen Primärschlüssel für die Sammlungstabelle und hat keine Möglichkeit, ihn zu erkennen welches Element der Sammlung geändert und löscht den alten Inhalt aus der Tabelle, um den neuen Inhalt einzufügen).

Aber, wenn du definierst ein @OrderColumn (um eine Spalte anzugeben, die verwendet wird, um die dauerhafte Reihenfolge einer Liste beizubehalten – was sinnvoll wäre, da Sie a verwenden List), Hibernate erstellt eine Primärschlüssel (aus der Order-Spalte und die Join-Spalte) und kann die Sammlungstabelle aktualisieren, ohne den gesamten Inhalt zu löschen.

Etwa so (wenn Sie den Standardspaltennamen verwenden möchten):

@Entity
public class Person {
    ...
    @ElementCollection
    @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
    @OrderColumn
    private List<Location> locations;
    ...
}

Verweise

  • JPA 2.0-Spezifikation
    • Abschnitt 11.1.12 „ElementCollection-Anmerkung“
    • Abschnitt 11.1.39 „OrderColumn Annotation“
  • JPA-Wikibook

  • Irgendwelche Ideen, wie man einen solchen Primärschlüssel mit Hibernate-XML-Mappings erstellt?

    – Funky Coder

    7. Januar 2013 um 14:23 Uhr

  • Ich habe das gleiche “Alle löschen”, “Zeile1 einfügen”, “Zeile2 einfügen” … SQL-Verhalten herausgefunden. Ich verwende OpenJPA2.2.2 und das Einfügen einer @Id-Anmerkung in eine einbettbare untergeordnete Entität hat nicht geholfen. OrderColumn erfordert eine neue Ganzzahl-Sortorder-DB-Spalte, und mein DB-Schema wird von dieser JPA-App nicht verwaltet, sodass dies möglicherweise keine Option ist.

    – Wen

    16. Oktober 2013 um 18:41 Uhr


  • Würde das auch mit einer Map funktionieren? Verwenden von MapKey (Join) Column usw. JPA erledigt das Löschen immer für mich.7

    – phil294

    11. Dezember 2017 um 20:57 Uhr

  • Weiß jemand, ob diese Lösung für grundlegende Sammlungen funktioniert? (z. B. würde es funktionieren, wenn das Feld List anstelle von List wäre) Oder funktioniert es nur mit Embeddables?

    – molinab297

    3. September 2019 um 22:03 Uhr


  • @ molinab297 ja, es funktioniert für grundlegende Sammlungen. Das Problem bei der obigen Lösung besteht darin, dass beim Löschen des ersten Elements der Liste der Index aller Elemente aktualisiert wird (um eine Position nach links verschoben).

    – Uri Loya

    18. Dezember 2019 um 7:55 Uhr


Hibernate @ElementCollection Seltsames Verhalten beim LoschenEinfugen
Vlad Mihalcea

Zusätzlich zu Pascals Antwort müssen Sie auch mindestens eine Spalte auf NOT NULL setzen:

@Embeddable
public class Location {

    @Column(name = "path", nullable = false)
    private String path;

    @Column(name = "parent", nullable = false)
    private String parent;

    public Location() {
    }

    public Location(String path, String parent) {
        this.path = path;
        this.parent= parent;
    }

    public String getPath() {
        return path;
    }

    public String getParent() {
        return parent;
    }
}

Diese Anforderung ist dokumentiert in AbstractPersistentCollection:

Problemumgehung für Situationen wie HHH-7072. Wenn das Sammlungselement eine Komponente ist, die vollständig aus Nullable-Eigenschaften besteht, müssen wir derzeit die gesamte Sammlung zwangsweise neu erstellen. Weitere Informationen finden Sie unter Verwendung von hasNotNullableColumns im AbstractCollectionPersister-Konstruktor. Um Zeile für Zeile zu löschen, würde dies SQL wie “WHERE ( COL = ? OR ( COL is null AND ? is null ) )” erfordern und nicht das aktuelle “WHERE COL = ?” (schlägt bei null für die meisten DBs fehl). Beachten Sie, dass der Parameter zweimal gebunden werden müsste. Bis wir dem AST in ORM 5+ schließlich „Parameterbindungspunkte“-Konzepte hinzufügen, ist der Umgang mit dieser Art von Bedingung entweder extrem schwierig oder unmöglich. Das Erzwingen der Wiederherstellung ist nicht ideal, aber nicht wirklich eine andere Option in ORM 4.

  • Jeez, danke Mann! Ich habe stundenlang damit gekämpft @ElementCollection, @OrderColumn, @Embeddable und @UniqueConstraints zusammen verwendet. Beim Entfernen oder Ändern der Reihenfolge der java.util.List Ich habe eine Verletzung der Eindeutigkeitsbeschränkung erhalten, weil Hibernate versucht hat, ein Update durchzuführen, anstatt die gesamte Sammlung zu löschen. Ändern der Felder der Klasse gekennzeichnet als @Embeddable nullable zu sein hat den Zweck erfüllt!

    – Jäger

    20. Oktober 2015 um 10:27 Uhr


  • Es scheint, dass es im neuesten Hibernate (5.2.3) nicht mehr relevant ist, ob die Spalten nullable sind oder nicht. Das Update scheint jedes Mal ausgeführt zu werden, was eigentlich unglücklich für meine App ist, da ich alle Sammlungselemente löschen und dann ersetzen muss, da ich eine habe @UniqueConstraints die verletzt wird, wenn das Update ausgeführt wird. Ziehe in Erwägung nach zu ziehen @OneToMany mit @OrderColumn und diese eindeutige Einschränkung als Primärschlüssel definieren … na ja …, wenn es überhaupt möglich ist, mal sehen.

    – Jäger

    19. Oktober 2016 um 15:02 Uhr


  • Sie können ein Jira-Problem hinzufügen, wenn Sie der Meinung sind, dass es sich um eine Regression handelt

    – Vlad Mihalcea

    19. Oktober 2016 um 15:50 Uhr

Wir haben festgestellt, dass Entitäten, die wir als unsere ElementCollection-Typen definiert haben, keine hatten equals oder hashcode Methode definiert und hatte nullable Felder. Wir haben diese (über @lombok für das, was es wert ist) für den Entitätstyp bereitgestellt, und es ermöglichte dem Ruhezustand (v 5.2.14), zu erkennen, ob die Sammlung schmutzig war oder nicht.

Außerdem hat sich dieser Fehler bei uns manifestiert, weil wir uns innerhalb einer Dienstmethode befanden, die mit der Anmerkung gekennzeichnet war @Transaction(readonly = true). Da der Ruhezustand versuchen würde, die zugehörige Elementsammlung zu löschen und erneut einzufügen, schlägt die Transaktion fehl, wenn sie geleert wird, und die Dinge brechen mit dieser sehr schwer nachzuvollziehenden Nachricht:

HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]

Hier ist ein Beispiel für unser Entitätsmodell, das den Fehler aufwies

@Entity
public class Entity1 {
@ElementCollection @Default private Set<Entity2> relatedEntity2s = Sets.newHashSet();
}

public class Entity2 {
  private UUID someUUID;
}

Ändern Sie es zu diesem

@Entity
public class Entity1 {
@ElementCollection @Default private Set<Entity2> relatedEntity2s = Sets.newHashSet();
}

@EqualsAndHashCode
public class Entity2 {
  @Column(nullable = false)
  private UUID someUUID;
}

Unser Problem wurde behoben. Viel Glück.

Ich hatte das gleiche Problem, wollte aber eine Liste von Aufzählungen zuordnen: List<EnumType>.

Ich habe es so zum Laufen gebracht:

@ElementCollection
@CollectionTable(
        name = "enum_table",
        joinColumns = @JoinColumn(name = "some_id")
)
@OrderColumn
@Enumerated(EnumType.STRING)
private List<EnumType> enumTypeList = new ArrayList<>();

public void setEnumList(List<EnumType> newEnumList) {
    this.enumTypeList.clear();
    this.enumTypeList.addAll(newEnumList);
}

Das Problem bei mir war, dass die List Das Objekt wurde immer mit dem Standard-Setter ersetzt und daher vom Ruhezustand als ein völlig “neues” Objekt behandelt, obwohl sich die Aufzählungen nicht geändert haben.

843090cookie-checkHibernate – @ElementCollection – Seltsames Verhalten beim Löschen/Einfügen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy