tl; dr
La chiave che non è tanto nulla in primavera dati REST - come si può facilmente farlo funzionare nello scenario - ma fare in modo che il vostro modello mantiene entrambe le estremità della associazione in sync.
Il problema
Il problema che vedete qui deriva dal fatto che la primavera dati REST modifica sostanzialmente la proprietà books
del vostro AuthorEntity
. Questo non riflette questo aggiornamento nella proprietà authors
di BookEntity
. Questo deve essere risolto manualmente, il che non è un vincolo di Spring Data REST ma il modo in cui funziona JPA in generale. Sarai in grado di riprodurre il comportamento errato semplicemente richiamando setter manualmente e cercando di mantenere il risultato.
Come risolvere questo?
Se rimuovere l'associazione bidirezionale non è un'opzione (vedere di seguito il motivo per cui lo consiglierei) l'unico modo per farlo funzionare è assicurarsi che le modifiche all'associazione si riflettano su entrambi i lati. Di solito le persone prendono cura di questo aggiungendo manualmente l'autore al BookEntity
quando si aggiunge un libro:
class AuthorEntity {
void add(BookEntity book) {
this.books.add(book);
if (!book.getAuthors().contains(this)) {
book.add(this);
}
}
}
L'ulteriore se la clausola avrebbe fatto da aggiungere sul lato BookEntity
pure se si vuole fare in modo che anche i cambiamenti dall'altra parte vengono propagati. Il numero if
è fondamentalmente richiesto in quanto altrimenti i due metodi si chiamerebbero costantemente.
Spring Data REST, per impostazione predefinita utilizza l'accesso al campo in modo che in realtà non vi sia alcun metodo in cui inserire questa logica. Un'opzione sarebbe quella di passare all'accesso delle proprietà e inserire la logica nei setter. Un'altra opzione consiste nell'utilizzare un metodo annotato con @PreUpdate
/@PrePersist
che itera sulle entità e assicura che le modifiche siano riflesse su entrambi i lati.
eliminazione della causa principale del problema
Come si può vedere, questo aggiunge un bel po 'di complessità al modello di dominio.Come ho scherzato su Twitter ieri:
# 1 regola delle associazioni bi-direzionale: non usarli ... :)
solito semplifica la questione se si tenta di non usare bidirezionale relazione quando possibile e ricorrere piuttosto a un deposito per ottenere tutte le entità che costituiscono il retro dell'associazione.
Una buona euristica per determinare quale lato tagliare è pensare a quale parte dell'associazione è davvero fondamentale e cruciale per il dominio che si sta modellando. Nel tuo caso, direi che è assolutamente perfetto per un autore esistere senza libri scritti da lei. Il rovescio della medaglia, un libro senza un autore non ha molto senso. Così mi piacerebbe mantenere la proprietà authors
in BookEntity
ma introdurre il seguente metodo sul BookRepository
:
interface BookRepository extends Repository<Book, Long> {
List<Book> findByAuthor(Author author);
}
Sì, che impone a tutti i clienti che in precedenza potevano solo hanno invocato author.getBooks()
di lavorare ora con un repository. Ma sul lato positivo hai rimosso tutto il cruft dai tuoi oggetti di dominio e hai creato una chiara direzione di dipendenza dal libro all'autore lungo la strada. I libri dipendono dagli autori ma non viceversa.
Le associazioni bidirezionali devono essere mantenute manualmente nel modello di oggetto che viene solitamente eseguito all'interno dei setter. Spring Data REST utilizza l'accesso al campo per impostazione predefinita. Ciò significa che il cambiamento delle associazioni non si riflette sull'altro lato dell'associazione per definizione. Hai provato, attivando la sincronizzazione in un metodo '@ PrePersist' /' PreUpdate'? O passare all'accesso alla proprietà? –
Vorrei anche votare per risolvere l'associazione bidirezionale. Un 'Autore' può esistere senza un' Libro'. 'Book's per un' Author' può essere recuperato utilizzando un metodo di repository 'Set BookRepository.findByAuthor (autore autore)'. Questo semplifica il modello un po 'perché non è necessario mantenere manualmente i riferimenti. –
Potrei vedere un'interfaccia di libreria dove è necessario trovare un autore, quindi visualizzare i suoi libri. Questo non sarebbe supportato senza associazioni bidirezionali. Non è un fan della gestione delle associazioni di entità se non è l'intento di DATA REST. Grazie per l'input e il filtro per gli autori di libri sembra essere l'approccio migliore. Non mantenere le cose unidirezionali quando possibile. :) – keaplogik