Ich habe zwei Tabellen, b und a:

  • Sie haben eine bidirektionale Eins-zu-Eins-Beziehung
  • a hat einen Fremdschlüssel für b, der diese Beziehung definiert
  • Dieser Fremdschlüssel wird auch als Primärschlüssel für a und als JPA @ID betrachtet.
  • Ich möchte eine Kaskadenentfernung, die das zugehörige b löscht, wenn a gelöscht wird
  • In MySQL ist a b_id NOT NULL

Das Problem ist, dass ich beim Löschen meines A Objekts mit dem JPA-Repository ein ConstraintViolationException auf seinem Fremdschlüssel erhalte. Ich würde erwarten, dass sowohl a als auch b Zeilen gelöscht werden (geschickt beginnend mit der a).

Wie könnte ich das umgehen, wenn ich weiß, dass ich behalten möchte:

  • Mein DB-Schema ist das gleiche
  • die Kaskadenentfernung von a nach b
  • Die b ID ist die JPA @Id für a
CREATE TABLE `b` (
  `dbid` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`dbid`),
);

CREATE TABLE `a` (
  `b_id` int(11) NOT NULL,
  KEY `b_fk` (`b_id`),
  CONSTRAINT `b_fk` FOREIGN KEY (`b_id`) REFERENCES `b` (`dbid`),
);

@Entity
@Table(name = "a")
public class A {

    @Id
    @Column(name = "b_id")
    @GeneratedValue(generator = "gen")
    @GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name="property", value="b"))
    private Integer bId;

    @OneToOne(cascade = CascadeType.REMOVE)
    @PrimaryKeyJoinColumn
    private B b;
}
@Entity
@Table(name = "b")
public class B {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name = "dbid")
    private Integer id;

    @OneToOne(mappedBy = "b")
    private A a;
}

[BEARBEITEN] Nach allen Diskussionen in Antwortkommentaren und erneutem Lesen meiner Frage sind die Vorschläge mit orphanRemoval tatsächlich in Umfang und Arbeit.

3
Pierre Mardon 19 Jän. 2019 im 17:12

4 Antworten

Beste Antwort

Wenn Sie ein Objekt von B löschen möchten, wann immer das zugehörige A gelöscht wird (dies ist der vierte Punkt Ihrer Wunschliste:

Ich möchte eine Kaskadenentfernung, die das zugehörige b löscht, wenn a gelöscht wird

Dann müssen Sie Ihre Zuordnung in A ändern in:

@OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true)
@PrimaryKeyJoinColumn
private B b;
1
Andronicus 29 Jän. 2019 im 16:23

Um das zu erreichen, was Sie gefragt haben, habe ich Ihre Tabellen wie folgt angepasst:

    CREATE TABLE b (
       dbid INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY
    );

    CREATE TABLE a ( 
       b_id int(11) NOT NULL PRIMARY KEY REFERENCES b(dbid) ON DELETE CASCADE
    );

CASCADE DELETE wurde Ihrer DDL nicht hinzugefügt.

Dadurch wird das Löschen von Kaskaden aktiviert. Um den b Datensatz beim Löschen von a zu löschen, habe ich folgende Änderungen in der Klasse A vorgenommen:

@Entity
@Table(name = "a")
public class A {

    @Id
    @Column(name = "b_id")
    @GeneratedValue(generator = "gen")
    @GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name="property", value="b"))
    private Integer bId;

    @OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true)
    @PrimaryKeyJoinColumn
    private B b;
}

Das hat gut funktioniert. Ich hoffe, es hilft.

Hier finden Sie einen Link zur funktionierenden Lösung.

1
Nisheeth Shah 30 Jän. 2019 im 11:00

Können Sie in Klasse B versuchen, Folgendes hinzuzufügen?

@OneToOne(mappedBy = "b", cascade = CascadeType.REMOVE)
private A a;

Wenn Sie in der Datenbank nur einen Fremdschlüssel haben, "a hat einen Fremdschlüssel für b", können Sie auch einen Fremdschlüssel von b nach a erstellen.

0
Periklis Douvitsas 23 Jän. 2019 im 18:49

Versuchen Sie es mit dem folgenden Code -

@OneToOne(mappedBy = "b",cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval=true )
private A a;
0
Narendra Pandey 29 Jän. 2019 im 10:27