PostgreSQL JPA - Löschen und orphanRemoval

rmacher01

Mitglied
Habe zwei folgende Entity-Klassen:

@Entity
public class Person {

@OneToOne
private Abteilung abteilung;

}

@Entity
public class Abteilung {

@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
private List<Person> mitearbeiterListe;
​
}

Wenn ich versuche, eine Abteilung zu löschen, bekomme ich die Meldung, das FK aus der Tabelle 'person' auf die Abteilung, die gelöscht werden soll, immer noch verweist.

public void deleteAbteilung(Abteilung a) {

// in Kurzform ...

EntityMangaer em = ...

em.getTransaction().begin();

if (!em.contains(abteilung)){

abteilung = em.merge(abteilung);​
}

em.remove(abteilung)

em.getTransaction().commit();
​
}

Fehlermeldung:
Caused by: org.postgresql.util.PSQLException: FEHLER: Aktualisieren oder Löschen in Tabelle „peson“ verletzt Fremdschlüssel-Constraint „fk_peson_abteilung_id“ von Tabelle „person“
Detail: Auf Schlüssel (id)=(20170) wird noch aus Tabelle „person“ verwiesen.


Irgendwie komme ich nicht weiter, denn auch cascade=CascadeType.REMOVE hat nicht geholfen. Wie löscht man so etwas (bidirektionale Association)?

(arbeite mit PostgreSQL und eclipselink)

Zusatzinfos:
  • Die Person ist an sich ein Angestelter und muss eine Abteilung-Referenz haben, während die Abteilung auch ohne Personen (Mitarbeiter) existieren kann.
  • Habe auch versucht, zuerst die Person-Instanzen aus der Liste zu löschen und erst dann die Abteilung, hat nicht geklapt (alles in einer Transaktion)
  • Das Löschen muss in einer Transaktion erfolgen, um im Falle dass es nicht klappt, ein rollback machen zu können.

Danke
 
Zuletzt bearbeitet:
Zuerst einmal finde ich es fragwürdig, dass Personen gelöscht werden, nur weil die Abteilung gelöscht wird. Aber gut, dafür magst du Gründe haben.

Stutzig macht mich zuerst einmal, dass du manuell eine Transaction startest. In welchem Umfeld führst du den Code aus?

Einfach die Liste leeren, bevor du die Abteilung löschst, sollte bereits ausreichen.
 
Zuerst einmal finde ich es fragwürdig, dass Personen gelöscht werden, nur weil die Abteilung gelöscht wird. Aber gut, dafür magst du Gründe haben.

Stutzig macht mich zuerst einmal, dass du manuell eine Transaction startest. In welchem Umfeld führst du den Code aus?

Einfach die Liste leeren, bevor du die Abteilung löschst, sollte bereits ausreichen.

Zuerst einmal vielen Dank.

Nun, ich arbeite mit Tomcat und dazu noch ist die Ausgangslage in der Tat noch etwas komplizierter. Die obigen Entities sind an sich nur als Stellvertretter gedacht.

Zur Ausgangslage:

Es gebe noch die Entity "Raum" und eine Abteilung belegt mehrere Räume, ein Raum gehört immer nur einer Abteilung.

@Entity
public class Raum{

@OneToOne
private Abteilung abteilung;

}


Dazu noch kommt in die Klasse Abteilung eine wietere Liste für Räume:

@Entity
public class Abteilung {

@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
private List<Person> mitearbeiterListe;

@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
private List<Raum> raumListe;
​
}

Wenn eine Abteilung gelöscht wird, müssen auch alle Räume gelöscht werden, die von dieser Abteilung belegt werden (macht zwar in der Realität keinen Sinn, bei der echten Entity ist es aber so).

Kurz gesagt: wenn eine Abteilung gelöscht wird, müssen alle Personen und Räume gelöscht werden, und dass alles in einer Transaktion (um rollback zu ermöglichen).

Ich habe herausgefunden, dass das Problem von der Bidirektionalität kommt. Wenn die Abteilung weben 'orphanRemoval' versucht, eine Person zu löschen, wird wegen der Referenz Person --> Abteilung versucht, die Abteilung zu löschen. Dies geht aber nicht, da es Räume gibt, die auf die Abteilung verweisen. Aus diesem Grund kann das nicht in einer Transaktion gelöscht werden: so stelle ich es mir vor.

Fall 1: Abteilung hat nur Personen aber keine Räume: Löschen funktioneirt
Fall 2: Abteilung hat nur Räume und keine Personen: Löschen funktioniert
Fall 3: Abteilung hat sowohl Personen als auch Räume: Löschen funktioniert nicht

Vorübergehende Lösung:
  • die Referenzen auf Abteilung in Person und Raum können Null sein
  • in einer ersten Transaktion werden diese Referenzen auf Null gesetzt und die dazugehörigen Personen und Räume updatet (commit inklusive)
  • in einer zweiten Transaktion wird die Abteilung gelöscht
So funktioniert es, allerdings kann ich im Fall, dass die zweite Transaktion misslingt, keinen echten Rollback machen. Da es sich aber um nur zwei Referenzen handelt, wird (zurzeit) in die Logdatei das Nötige geschrieben so das man im Notfall es von Hand noch anpassen kann (die Wahrscheinlichkeit, dass so was passiert ist eher sehr gering).

So sieht meine jetzige Lösung aus. Wenn es da bessere Möglichkeiten gebe, wäre ich um jeden Hinweis sehr froh.
 
Du hast im hier geposteten Code nirgends ein bidirectionales Mapping, ich hoffe das ist dir klar?!

Das ist korrekt: Die echten bidirektionalen Assoziationen gibt es in der Tat nicht. Mit "Bidirektionalität" habe ich (vielleicht etwas unglücklich) die Tatsache gemeint, dass z.B. eine Abteilung Referenzen auf eine oder mehrere Personen hat, wobei diese wiederum auf die Abteilung je eine Referenz haben (dito mit Räumen). Das Problem kommt vermutlicht dacher, dass diese gerade zweimal vorkommt: einmal mit Personen und einmal mit Räumen.
 
Du schreibst ziemlich unverständlich. Obendrein postest du nur unvollständigen Code, der ja offenbar dein Problem gar nicht so genau widerspiegelt. Da ist es nicht leicht dir zu helfen ._.
 
Du schreibst ziemlich unverständlich. Obendrein postest du nur unvollständigen Code, der ja offenbar dein Problem gar nicht so genau widerspiegelt. Da ist es nicht leicht dir zu helfen ._.

Sorry (habe am Anfang selbst nicht realisiert, dass das Problem möglicherweise wo anders liegt). Falls möglich, diesen Thread am besten löschen.
 

Neue Themen


Zurück
Oben