Comment maintenir bi-directionnelle des relations avec le Printemps, les Données de REPOS et de JPA?
De travail avec le Printemps des Données RESTE, si vous avez un OneToMany
ou ManyToOne
relation, l'opération de placement des rendements de 200 sur la "non-propriétaire" de l'entité, mais n'en fait persister le joint de ressources.
Exemple Entités:
@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
}
Si vous en arrière avec un PagingAndSortingRepository
, vous pouvez OBTENIR un Book
, suivez les authors
lien sur le livre et d'en faire un avec l'URI d'un auteur à associer avec. Vous ne pouvez pas aller dans l'autre sens.
Si vous faire un GET sur un Auteur et faire METTRE sur son books
lien, la réponse renvoie à 200, mais la relation n'est jamais conservée.
Est-ce le comportement attendu?
- Bi-directionnel associations doivent être gérés manuellement dans le modèle d'objet qui est généralement fait à l'intérieur des organismes de normalisation. Printemps de Données RESTE utilise le champ d'accès par défaut. Que signifie le changement dans les associations ne se reflète pas sur l'autre côté de l'association, par définition. Avez-vous essayé, le déclenchement de la synchronisation dans un
@PrePersist
/@PreUpdate
méthode? Ou de passer à l'accès à la propriété? - J'avais aussi le droit de vote pour résoudre le bidirectionnel de l'association. Un
Author
peut exister sans unBook
.Book
s pour unAuthor
peuvent être récupérées en utilisant un référentiel méthodeSet<Book> BookRepository.findByAuthor(Author author)
. Cela simplifie le modèle tout à fait un peu comme vous n'avez pas à maintenir manuellement les références. - J'ai pu voir une interface de la bibliothèque où vous auriez besoin de trouver un auteur, puis affichez-les livres. Ce ne serait pas être pris en charge sans bi-directionnelle des associations. Pas fan de la gestion des entités, associations, si elle n'est pas l'intention de DONNÉES de REPOS. Merci pour l'entrée, et le filtrage de l'auteur de livres semble être la meilleure approche. Ne pas garder les choses unidirectionnel chaque fois que possible. 🙂
Vous devez vous connecter pour publier un commentaire.
tl;dr
La clé qui n'est pas tellement quelque chose au Printemps de Données RESTE - comme vous pouvez facilement le faire fonctionner dans votre scénario - mais assurez-vous que votre modèle garde les deux extrémités de l'association dans la synchro.
Le problème
Le problème que vous voyez ici provient du fait que les Données du Printemps RESTE fondamentalement modifie le
books
propriété de votreAuthorEntity
. Que lui-même ne reflète pas cette mise à jour dans leauthors
propriété de laBookEntity
. Ce doit être travaillé autour de la main, ce qui n'est pas une contrainte qui Ressort des Données de REPOS fait, mais la manière dont JPA œuvres en général. Vous serez en mesure de reproduire l'erreur de comportement en invoquant simplement setters manuellement et en essayant de conserver le résultat.Comment résoudre ce problème?
Si la suppression de la bi-directionnel de l'association n'est pas une option (voir ci-dessous pourquoi je recommande cet) la seule façon de faire de ce travail est de s'assurer que les changements de l'association sont répercutées sur les deux côtés. Habituellement, les gens prendre soin de cela en ajoutant manuellement à l'auteur de la
BookEntity
quand un livre est ajouté:Supplémentaires si l'alinéa aurait à ajouter sur le
BookEntity
côté si vous voulez faire en sorte que les modifications de l'autre côté sont propagées, trop. Leif
est fondamentalement nécessaire sinon les deux méthodes n'auront de cesse de s'appellent eux-mêmes.Printemps de Données RESTE, par défaut, utilise accès sur le terrain de sorte qu'il y a en fait aucune méthode que vous pouvez mettre cette logique dans. Une option serait de passer à l'accès à la propriété et de mettre de la logique dans les organismes de normalisation. Une autre option est d'utiliser une méthode annotée avec
@PreUpdate
/@PrePersist
qui effectue une itération sur les entités et permet de s'assurer que les modifications sont répercutées sur les deux côtés.Retrait de la cause racine du problème
Comme vous pouvez le voir, ce qui ajoute beaucoup de complexité pour le modèle de domaine. Comme je l'ai plaisanté sur Twitter hier:
Habituellement, il simplifie la question si vous essayez de ne pas utiliser de bi-directionnelle relation chaque fois que possible et plutôt revenir à un référentiel d'obtenir toutes les entités qui composent l'arrière de l'association.
Une bonne heuristique pour déterminer de quel côté est la coupe de penser au côté de l'association est vraiment de base et essentiel pour le nom de domaine, vous êtes à la modélisation. Dans votre cas, je dirais qu'il est parfaitement bien pour un auteur pour exister sans les livres écrits par elle. Sur le revers de la médaille, un livre sans auteur ne fait pas trop de sens. Donc, je garderais le
authors
propriété dansBookEntity
mais introduire la méthode suivante sur laBookRepository
:Oui, qui exige que tous les clients qui ont précédemment pourrait juste avoir invoqué
author.getBooks()
à maintenant travailler avec un référentiel. Mais sur le côté positif que vous avez supprimé tous les fichiers inutiles de votre domaine d'objets et créé une nette dépendance de la direction du livre à l'auteur le long du chemin. Livres dépendent des auteurs, mais pas l'inverse.J'ai fait face à un problème similaire, lors de l'envoi de mon POJO(contenant bi-directionnelle de la cartographie @OneToMany et @ManyToOne) comme JSON via l'api REST, les données ont été persisté à la fois le parent et l'enfant entités, mais la clé étrangère de la relation n'a pas été établie. Cela se produit parce que bidirectionnel associations doivent être gérés manuellement.
JPA fournit une annotation
@PrePersist
qui peut être utilisé pour s'assurer que la méthode annotée avec elle est exécutée avant que l'entité n'est conservée. Depuis, JPA insère d'abord l'entité mère à la base de données, suivi par l'entité enfant, j'ai inclus une méthode annotée avec@PrePersist
qui permettrait de parcourir la liste des enfants et de définir manuellement l'entité mère pour elle.Dans votre cas, il serait quelque chose comme ceci:
Après cela, vous pouvez obtenir une récursivité infinie d'erreur, pour éviter que les annoter la classe parent avec
@JsonManagedReference
et votre enfant de la classe avec@JsonBackReference
. Cette solution a fonctionné pour moi, j'espère qu'il va travailler pour vous aussi.