2016-03-17 6 views
8

Ich entwickle ein relativ großes Projekt mit Spring Boot, und in einer allgemeinen Weise bin ich ziemlich glücklich damit, aber ich habe einige Probleme, dass in meinen Gedanken sollte kein Problem sein.Lazy One-To-One Frühling JPA und Gebäude "dynamische" JSON

  1. Vor allem, One-to-One-Beziehung. Es ist frustrierend, dass es nicht funktioniert (zumindest in meinen Gedanken).

    Ich habe zwei Entitäten, User und UserProfile, zum Beispiel. Sie haben One-to-One-Beziehung, aber die meiste Zeit brauche ich nur die User Daten, aber es holt (egal was ich versuche, und oh Junge, ich versuchte die Welt Vorschläge für jeden Post für 5 Seiten von Google).

    Also gibt es meine erste Frage, gibt es eine Möglichkeit, faul holen One-to-One-Beziehung in JPA und Spring? (Weil die meisten Beiträge mehr als 2-3 Jahre alt sind).

  2. Das andere Problem, das ich habe, ist im Begriff, eine JSON-Antwort in einer "dynamischen" Weise zu bauen. Ich habe einige Sachen mit Rails gemacht und war sehr glücklich mit JBuilder oder sogar der to_json, die mir die Fähigkeit gegeben hat, die JSON-Antwort je nach Controller und meinen Bedürfnissen im Moment zu erstellen.

    Im Frühjahr habe ich die folgenden Lösungen:

    • Jackson @JsonView (was nicht ganz mein Problem nicht lösen, weil die Antworten nicht, dass statische und ein Attribut sind, kann nicht auf mehrere Ansichten zugeordnet wird (soweit Ich habe das Konzept verstanden));
    • Einstellung auf Null-Attribute, die ich nicht auf die Antwort möchte (mit diesem, aber ich bin einfach zu hässlich und sieht aus wie eine falsche Walkthrough);
    • oder Gebäude HashMap wie ich baue .json.jbuilder auf Schienen (aber das tötet meine Leistung als manchmal hat es Beziehungen so viele for, um den JSON zu bauen, und auch das sieht aus wie eine hässliche Walkthrough).

Ich suche nach einigen Richtungen von jemandem, der eines Tages haben eines dieser Probleme, weil es bringt mich nicht in der Lage ist, so Probleme zu lösen, dass in meinem Kopf das nicht schwer sein sollte.

EDIT 1

bereits versucht optional = false auf der @OneToOne Anmerkung hinzuzufügen, um die Eager Last von OneToOne Beziehung zu lösen, wie @snovelli vorgeschlagen. Beispiel:

@OneToOne(optional=false, fetch = FetchType.LAZY) 
public UserProfile getUserProfile(){ ... } 
+0

Ihre Frage enthält zwei unabhängige Fragen. Sie sollten eine auswählen und die andere in eine separate Frage extrahieren. Wie auch immer, dies ist die erste SO-Frage, in der ich zwei Antworten hinzugefügt habe. :) –

+0

Ich dachte darüber nach, aber ich hatte einige Fragen wie diese, aber niemand antwortete, also postete ich diesen mit dem Wissen, dass ich ein Kopfgeld geben müsste, damit es beantwortet werden kann, und weil ich nicht zu viele Punkte habe um auf Bounties zu verschonen, lege ich die beiden in eine Frage :(Aber zumindest denke ich, das sind zwei Fragen, die jeder, der kein Assistent bei Spring und JPA ist, haben kann. – augustoccesar

Antwort

6

Wenn die Join-Spalte nicht in der Tabelle enthalten ist, der ein übergeordnetes Element in einer Eins-zu-Eins-Zuordnung zugeordnet ist, wird die Verknüpfung cannot be lazy. Der Grund dafür ist, dass der JPA-Provider nicht feststellen kann, ob der Proxy erstellt werden soll, damit er das Objekt bei späterem Zugriff laden kann, oder den Wert null beibehalten.

Auch wenn die Zuordnung nicht optional ist, muss der JPA-Provider die ID der verknüpften Entitätsinstanz ermitteln, um sie im Proxy zu speichern. Also muss es trotzdem zur zugehörigen Tabelle gehen.

Lösungen:

  1. Byte code instrumentation. Nicht weit verbreiteter Ansatz jedoch.
  2. Verwenden Sie Eins-zu-viele und behandeln Sie leere Liste als null, andernfalls verwenden Sie list.get(0). Sie können dies natürlich in der Entitätsklasse kapseln (Getter gibt das einzige Element der Liste oder null zurück). Der Nachteil ist, dass Sie dies als Sammlung in JPQL-Abfragen behandeln müssen.
  3. Verwenden Sie @PrimaryKeyJoinColumn anstelle eines Fremdschlüssels. Wenn die Zuordnung nicht optional ist (optional = false), dann weiß der JPA-Anbieter, dass ein untergeordnetes untergeordnetes Objekt mit derselben PK verknüpft ist. Daher wird nur das PK des übergeordneten Objekts als ID des untergeordneten Objekts im Proxy gespeichert. Natürlich können Sie nicht zwei unabhängige ID-Generatoren für beide Entitäten verwenden, da sich die PK sonst unterscheiden können. Dies ist der beste Ansatz, wenn er Ihren Anforderungen entspricht.
  4. Fügen Sie den Fremdschlüssel auch in der übergeordneten Tabelle hinzu (wodurch die Beziehung auch in der Datenbank bidirektional wird). Der Nachteil ist, dass Sie jetzt grundsätzlich zwei unabhängige Verknüpfungen haben, die Sie pflegen müssen. Außerdem gibt es die Kosten für die Aktualisierung von zwei Tabellen anstelle von einer (und die Fremdschlüssel müssen nullfähig sein).
  5. Map übergeordnete Entität in eine Datenbank Ansicht, die übergeordnete Tabelle mit der untergeordneten Tabelle verbindet und enthält alle übergeordneten Spalten und ID der Kinder Tabelle:

    @OneToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "<child id in the view>", insertable = false, updatable = false) 
    private Child child;
+0

Es hat mit dem dritten Vorschlag gut geklappt. Erschien ein Problem mit meine ID-Typ (es sagt, dass eine Ganzzahl, aber eine Long erwartet) aber nach dem Ändern der Art, die es funktionierte (das ist etwas, was ich später nachschlagen werde), das wichtige ist, dass es funktioniert. Danke! – augustoccesar

+0

@augustoccesar Gern geschehen Beachten Sie, dass Sie nicht zwei unabhängige ID-Generatoren für beide Entitäten mit der '@ PrimaryKeyJoinColumn' verwenden können, die zugehörigen Entitäten müssen dieselbe PK haben. –

+0

Mit der gleichen PK meinen Sie das auf der Cre Bei den beiden wird das gleiche Inkrement wie bei einem 'Benutzer' mit einer 'id == 1' verwendet, dann hat das zugehörige 'UserProfile' die 'id == 1'? – augustoccesar

0

In Bezug auf @OneToOne: Sind Sie besorgt, mehr nach Datenmenge oder mehr Abfragen für die DB?

In früheren Fall (wenn das bei der Verwendung von Spring Roo möglich ist) könnten Sie eine Problemumgehung mit @ManyToOne Relationsmodell versuchen (eins zu eins ist ein Sonderfall von eins zu eins, nicht wahr?).

In letzterem Fall könnten Sie @Embeddable verwenden, um eine Entität wie Benutzer in mehrere Klassen zu zerlegen, während die Daten in der DB zusammengehalten werden, sodass nur eine Abfrage verwendet wird, um sie abzurufen.

2

In Bezug auf ‚dynamische‘ JSON: Verwenden Sie DTOs.

Dies hat den Vorteil, dass die zu serialisierenden Objekte genau auf die Bedürfnisse des Clients zugeschnitten werden, der den resultierenden JSON verbraucht. Außerdem ist das Domänenmodell (Hibernate-Entitäten) von der JSON- (De-) Serialisierungslogik entkoppelt, so dass sich beide unabhängig entwickeln können.

+0

Das ist ein tolles Muster! Wusste darüber nicht. In gewisser Weise manipulierte ich die Antworten, aber mit HashMap. Die Verwendung von DTOs sieht korrekter und wartbarer aus. Vielen Dank! – augustoccesar

Verwandte Themen