Wie pflegt bi-direktionale Beziehungen mit Spring Data REST und JPA?
Arbeit mit Spring Data REST, wenn Sie eine OneToMany
oder ManyToOne
Beziehung, die PUT-operation gibt 200 auf die "nicht-Besitz" - Entität, aber nicht tatsächlich bestehen die verknüpfte Ressource.
Beispiel Unternehmen:
@Entity(name = 'author')
@ToString
class AuthorEntity implements Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
String fullName
@ManyToMany(mappedBy = 'authors')
Set<BookEntity> books
}
@Entity(name = 'book')
@EqualsAndHashCode
class BookEntity implements Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
@Column(nullable = false)
String title
@Column(nullable = false)
String isbn
@Column(nullable = false)
String publisher
@ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
Set<AuthorEntity> authors
}
Wenn Sie wieder mit einem PagingAndSortingRepository
können Sie eine Book
Folgen Sie den authors
link auf das Buch und nicht eine mit der URI von einem Autor zuordnen. Sie können den anderen Weg gehen.
Wenn Sie ein GET auf einen Autor und eine auf Ihre books
link, die Antwort gibt 200, aber die Beziehung wird nie gespeichert.
Ist dies das erwartete Verhalten?
- Bi-direktionale Assoziationen müssen manuell verwaltet werden, in das Objekt-Modell, das erfolgt in der Regel innerhalb des setters. Spring Data REST verwendet field access standardmäßig. Das bedeutet, dass die änderung in vereinen wird nicht widergespiegelt, auf der anderen Seite des Vereins per definition. Haben Sie versucht, die Auslösung der Synchronisation in einem
@PrePersist
/@PreUpdate
Methode? Oder wechseln Sie zu Eigenschaften zugreifen? - Ich würde auch Stimmen zu beheben, die eine bidirektionale Assoziation. Ein
Author
existieren kann ohne einBook
.Book
s für eineAuthor
abgerufen werden können, mithilfe eines repository-MethodeSet<Book> BookRepository.findByAuthor(Author author)
. Dies vereinfacht das Modell ganz ein bisschen, wie Sie nicht haben, um manuell verwalten, Referenzen. - Ich konnte sehen, eine library-Schnittstelle, wo würden Sie brauchen, zu finden, ein Autor, wenn es dann Bücher. Dies würde nicht unterstützt werden, ohne die bi-direktionale Assoziationen. Nicht ein fan von der Verwaltung der Entitäten, die Assoziationen, wenn es nicht die Absicht, DATEN REST. Vielen Dank für den input und die Filterung für die Autorin der Bücher zu sein scheint der beste Ansatz. Nicht, um die Dinge einseitig, Wann immer möglich. 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
tl;dr
Den Schlüssel zu diesem ist nicht so sehr etwas in Spring Data REST - wie können Sie es leicht zu bekommen Ihre Arbeit in der Szenario - aber machen Sie sicher, dass Ihr Modell hält beide enden der Assoziation in sync.
Das problem
Das problem, das Sie hier sehen, ergibt sich aus der Tatsache, dass Spring Data REST im Grunde ändert das
books
Eigentum IhrerAuthorEntity
. Das selbst spiegelt nicht das update in derauthors
Eigenschaft desBookEntity
. Dies muss manuell umgangen werden, das ist nicht eine Einschränkung, Spring Data REST macht aber die Art und Weise, dass der PPV im Allgemeinen funktioniert. Sie werden in der Lage sein, zu reproduzieren, die ein fehlerhaftes Verhalten durch den Aufruf einfach setter manuell und versuchen, speichern Sie das Ergebnis.Wie man dieses Problem lösen?
Wenn das entfernen der bi-direktionale Assoziation ist keine option (siehe unten, warum ich würde empfehlen dies) der einzige Weg, um diese Arbeit zu machen ist, um sicherzustellen, dass änderungen an den Verein wider auf beiden Seiten. In der Regel Menschen, die sich darum kümmern, indem Sie manuell hinzufügen, die der Autor auf die
BookEntity
wenn ein Buch Hinzugefügt:Die zusätzliche if-Klausel haben würde, zusätzlich auf die
BookEntity
Seite-wenn Sie möchten, stellen Sie sicher, dass änderungen, die von der anderen Seite weitergegeben werden, auch. Dieif
ist grundsätzlich erforderlich, da andernfalls die beiden Methoden würde ständig sich selbst nennen.Spring Data REST, standardmäßig verwendet field access, so dass es eigentlich keine Methode, dass Sie diese Logik in. Eine Möglichkeit könnte sein, wechseln Sie zu Eigenschaften zugreifen und die Logik in den setter. Eine weitere option ist die Verwendung einer Methode annotiert mit
@PreUpdate
/@PrePersist
dass er iteriert über die Personen und stellt sicher, dass die änderungen spiegeln sich auf beiden Seiten.Entfernen der Ursache des Problems
Wie Sie sehen können, diese fügt sehr viel Komplexität das domain-Modell. Als ich scherzte auf Twitter gestern:
Es in der Regel vereinfacht die Sache, wenn Sie versuchen, nicht zur Verwendung von bi-direktionale Beziehung, wenn immer möglich und eher zurückgreifen, um ein repository an, um alle Entitäten, aus denen die Rückwand des Vereins.
Eine gute Heuristik, um zu bestimmen, welche Seite zu schneiden, ist zu überlegen, welche Seite von dem Verein ist wirklich Kern und ist entscheidend für die domain, an die Sie modellieren. In deinem Fall würde ich argumentieren, dass es völlig in Ordnung, für einen Autor besteht keine Bücher von Ihr geschrieben. Auf der anderen Seite, ein Buch ohne einen Autor nicht viel Sinn zu machen überhaupt. Also ich würde halten Sie die
authors
Eigenschaft inBookEntity
sondern führen Sie die folgende Methode auf dieBookRepository
:Ja, dass erfordert, dass alle clients, die bisher nur angerufen haben
author.getBooks()
jetzt die Arbeit mit einem repository. Aber auf der positiven Seite, du hast entfernt alle Reste von Ihrem domain-Objekte und erstellt eine klare Abhängigkeit der Richtung von Buch Autor mit auf den Weg. Büchern hängen von Autoren, aber nicht Umgekehrt.Stand ich vor einem ähnlichen problem, beim senden meiner POJO(mit bi-direktionale mapping @OneToMany und @ManyToOne) als JSON über REST-api, die Daten beibehalten, in übergeordnete und untergeordnete Einheiten, sondern die foreign-key-Beziehung nicht eingerichtet. Dies geschieht, weil die bidirektionale Verknüpfungen müssen manuell verwaltet werden.
JPA bietet eine Anmerkung
@PrePersist
verwendet werden können, um sicherzustellen, dass die Methode annotate es wird ausgeführt, bevor entity persistiert. Da JPA ersten Einsätze der übergeordneten Entität in die Datenbank, gefolgt von der untergeordneten Entität, habe ich eine Methode annotiert mit@PrePersist
würde eine Iteration durch die Liste der untergeordneten Einheiten, und legen Sie manuell die übergeordnete Entität zu.In Ihrem Fall, es wäre so etwas wie dieses:
Nach dieser erhalten Sie möglicherweise eine Endlosschleife Fehler, um zu vermeiden, dass Anmerkungen in Ihren übergeordneten Klasse mit
@JsonManagedReference
- und Ihr Kind-Klasse mit@JsonBackReference
. Diese Lösung funktionierte für mich, hoffentlich wird es für Sie zu arbeiten.