2017-07-08 4 views
0

beeinflussen habe ich eine Beziehung zwischen Eltern (Eigenschaften) und Kinder (Credit), meine Hibernate Konfiguration funktioniert für mich so lange in Ordnung Ich versuche, don `t um ein neues Child (Guthaben) durch Cascade über das Parent (Property) zu speichern.JPA/Hibernate @OneToMany optional mit Kind auf JoinTable - Speichern Eltern mehrere Einsätze auf JoinTable

Hibernate-Konfigurationen:

@Entity 
public class Property implements Ownable { 

    ... 

     @Valid 
     // ALSO TRIED WITH CascadeType.ALL !!! 
     @OneToMany(fetch = LAZY, cascade = {PERSIST, MERGE, REMOVE}, orphanRemoval = true) 
     @JoinTable(
       name = "PROPERTY_CREDIT_OPTIONS", 
       joinColumns = @JoinColumn(name="PROPERTY_ID", nullable = false), 
       inverseJoinColumns = @JoinColumn(name = "CREDIT_ID", nullable = false, unique = true) 
     ) 
     List<NotActiveCredit> creditOptions = new ArrayList<>(); 

    ... 

} 

@Entity 
public class NotActiveCredit extends Credit { 

    @ManyToOne 
    @JoinTable(
     name    = "PROPERTY_CREDIT_OPTIONS", 
     inverseJoinColumns = @JoinColumn(name="PROPERTY_ID", nullable = false), 
     joinColumns   = @JoinColumn(name = "CREDIT_ID", nullable = false, unique = true) 
    ) 
    @NotNull @NonNull 
    Property property; 
} 

Controller-Call:

@PostMapping("/save") 
public String save (
     @ModelAttribute("property") @Valid Property formProperty, 
     BindingResult errors, 
     ModelMap modelMap 
) { 
    if (!errors.hasErrors()) { 

     // formProperty has new Credit in the creditOptions List 
     // SAVE ONLY DELEGATS TO SPRING DATA REPOSITORY ... 
     final Property savedProperty = propertyService.save(formProperty); 
     ...  

    } else { 
     // BLABLA 
    } 
} 

Die Protokollierung wie folgt aussieht:

Enter InvestmentController.save(...) 
Enter PropertyServiceImpl.save(...) 

insert into not_active_credit (id, interest_rate_nominal_in_percent, name_of_institution, redemption_at_begin_in_percent, special_redemption_each_year_in_percent) values (default, ?, ?, ?, ?) 
binding parameter [1] as [NUMERIC] - [null] 
binding parameter [2] as [VARCHAR] - [test] 
binding parameter [3] as [NUMERIC] - [null] 
binding parameter [4] as [NUMERIC] - [null] 

insert into property_credit_options (property_id, credit_id) values (?, ?) 
binding parameter [1] as [BIGINT] - [1] 
binding parameter [2] as [BIGINT] - [1] 

Exit PropertyServiceImpl.save Returns Property 

// THEN WHEN IT CLOSE THE TRANSACTION IT WANTS TO INSERT JOIN TABLE AGAIN! 
insert into property_credit_options (property_id, credit_id) values (?, ?) 
binding parameter [1] as [BIGINT] - [1] 
binding parameter [2] as [BIGINT] - [1] 

SQL Error: -104, SQLState: 23505 
integrity constraint violation: unique constraint or index violation; SYS_PK_10222 table: PROPERTY_CREDIT_OPTIONS 

Mein Object`s Inhalt enter image description here Alle Hinweise sind sehr willkommen.

Bearbeiten: Zusätzliche Informationen. Nach dem Aufruf des Repository. Speichern Sie die Liste wird immer noch als schmutzig (schmutzig = wahr). Sollte es nicht falsch sein, wenn es gerade gespeichert wurde, weil ich es in der Konsole sehen kann, senden Sie einfach SQL an db, indem Sie eine Einfügung machen. Beim Debuggen, wenn ich der Liste das dirty = false gebe, wird das Einfügen zum zweiten Mal nicht mehr ausgelöst und alles ist in Ordnung. Warum wird es nicht auf false gesetzt, nachdem Einfügungen an die DB gesendet wurden? Es sollte nicht mehr schmutzig sein, oder denke ich falsch?

SOLUTION

Als crizzis schlug ich @JoinTable aus der Sammlung Eigenschaft creditOptions in Klasse Property entfernt und mappedBy='property' hinzugefügt. Die Sammlung ist jetzt von übergeordneten Elementen aktualisierbar.

@Valid 
@OneToMany(mappedBy="property", fetch = LAZY, cascade = ALL, orphanRemoval = true) 
Collection<NotActiveCredit>  creditOptions = new ArrayList<>(); 

Auf der anderen Seite auf Klasse NotActiveCredit es ist wie folgt:

@ManyToOne 
@JoinTable(
     name    = "PROPERTY_CREDIT_OPTIONS", 
     inverseJoinColumns = @JoinColumn(name="PROPERTY_ID", nullable = false), 
     joinColumns   = @JoinColumn(name = "CREDIT_ID", nullable = false, unique = true) 
) 
@NotNull 
Property property; 

Antwort

1

Der Grund der Verein Eintrag zweimal in der Join-Tabelle eingefügt wird, ist, dass Sie tatsächlich zwei separate deklariert haben Assoziationen (die zufällig dieselbe Join-Tabelle verwenden) intead von nur einer.

Wenn eine bidirektionale Assoziation in JPA Modellierung, von der Seite muß die besitzenden Seiten , und die andere Seite muss die inverse Seite sein sein. Die umgekehrte Seite ist diejenige, deren Assoziationszuordnung das Attribut mappedBy deklariert.

Die Lösung besteht einfach darin, eine der Seiten der Assoziation als die inverse Seite zu deklarieren und die Annotation von dieser Seite zu entfernen. Andernfalls behandelt JPA jede Seite als separate unidirektionale Assoziation.

Beachten Sie, dass für alle JPA weiß, könnten Sie aus irgendeinem Grund zwei separate unidirektionale Verknüpfungen (z. B. mit anderen Join-Tabellen) haben möchten. JPA kennt Ihre Absichten einfach nicht automatisch - Sie benötigen das Attribut mappedBy, um sie klarzustellen.

+0

Hey, toll, ich habe gerade JoinTable aus der 'NotActiveCredit' Klasse entfernt und es funktioniert schon. 'mappedBy' war nicht notwendig. –

+0

Dies wird weiterhin als separate Zuordnung behandelt. Der einzige Unterschied ist, dass '@ ManyToOne' standardmäßig eine Join-Spalte verwendet, so dass Sie wahrscheinlich eine zusätzliche' PROPERTY_ID'-Spalte in der 'NONACTIVECREDIT'-Tabelle sehen werden. Außerdem werden 'Property.creditOptions' und' NotActiveCredit.property' von JPA * nicht ** synchron gehalten. – crizzis

+0

Die Tabelle 'not_active_credit' hat nur eine' property_id' erstellt, aber ich werde die Synchronisation genauer betrachten . Übrigens. Die Annotation @ManyToOne hat kein 'mappedBy', wo würden Sie vorschlagen, es hinzuzufügen? Vielen Dank. –

Verwandte Themen