Comment éviter les doublons avec JPA cascades?
J'ai un Parent entité avec un Enfant entité dans un ManyToOne relation:
@Entity class Parent {
//...
@ManyToOne((cascade = {CascadeType.ALL})
private Child child;
//...
}
La Enfant a un champ unique:
@Entity class Child {
//...
@Column(unique = true)
private String name;
//...
}
Quand j'ai besoin d'un nouveau Enfant, je demande à la ChildDAO première:
Child child = childDao.findByName(name);
if(child == null) {
child = new Child(name);
}
Parent parent = new Parent();
parent.setChild(child);
Le problème est que si je fais comme ci-dessus deux fois (avec le même nom pour le Enfant), et ne persiste que l' Parent à la fin, j'obtiens une contrainte d'exception. Ce qui semble normal, car au début il n'y avait pas d'enfant dans la base de données avec le nom spécifié.
Le problème est, je ne suis pas sûr de ce que serait la meilleure façon d'éviter cette situation.
Êtes-vous sûr que votre modèle est bien? L'enfant peut avoir de nombreux Parents, et Parents peut avoir qu'un seul Enfant?
Ma réponse suppose une relation OneToOne - le commentaire ci-dessus est tout à fait exact, c'est un nom bizarre si elle est correcte.
Oui, le modèle est correct. J'ai renommé les entités pour l'exemple, et il semble que j'aurais pu faire mieux.
Ma réponse suppose une relation OneToOne - le commentaire ci-dessus est tout à fait exact, c'est un nom bizarre si elle est correcte.
Oui, le modèle est correct. J'ai renommé les entités pour l'exemple, et il semble que j'aurais pu faire mieux.
OriginalL'auteur Cos64 | 2011-11-27
Vous devez vous connecter pour publier un commentaire.
Vous êtes à la création de deux instances persistantes de l'Enfant
new Child()
deux fois, puis les mettre dans ces deux Parents différents. Lorsque vous persister le Parent objets, chacune des deux nouvelles instances Enfant sera persisté/inséré par l'intermédiaire cascade, chacune avec une autre@Id
. La contrainte unique sur le nom puis les pauses. Si vous êtes en train de faire CascadeType.TOUS, chaque fois que vous nenew Child()
vous pouvez peut-être obtenir un distinct objet persistant.Si tu voulais vraiment les deux instances Enfant à être traités comme un seul objet persistant avec le même ID, vous devez persister séparément à associer avec le contexte de persistance/session. Les appels suivants à
childDao.findByName
serait ensuite rincer l'insertion et de retour de l'Enfant, vous venez de créer, de sorte que vous n'aurez pas à fairenew Child()
deux fois.OriginalL'auteur wrschneider
Vous obtenez ce parce que vous tentez de persistance d'un objet qui existe déjà (même IDENTIFIANT). Votre cascade n'est probablement pas persister c'est de FUSION/mise à JOUR/SUPPRIMER/DÉTACHER. La meilleure façon d'éviter cette situation est configuré de la cascade correctement ou de gérer les cascades manuellement. Fondamentalement parlant, en cascade persiste est le coupable habituel.
Probable que vous voulez quelque chose comme ceci:
Les cascades peuvent être extrêmement frustrant si vous laissez le cadre de la gérer parce que vous manquez de temps en temps des mises à jour si elle est mise en cache (en particulier avec des Collections dans les relations ManyToOne). Si vous n'avez pas explicitement enregistrer le parent et permettent le cadre de traiter avec les cascades. De manière générale, je permettre une Cascade.TOUS mes parents dans une relation et une cascade de tous les SUPPRIMER/PERSISTENT à partir de mes enfants. Je suis un Eclipselink utilisateur donc mon expérience avec Hibernate/autres est limité et je ne peux pas parler à la mise en cache.
* Vraiment, pensez-y-si vous êtes économiser de l'enfant voulez-vous vraiment à enregistrer tous les objets qui y sont associés? Aussi, si vous êtes l'ajout d'un enfant, ne devrait pas vous aviser le parent? *
Dans votre cas, je voudrais simplement avoir un "saveParent" et "saveChild" de la méthode dans mon Dao/Service qui fait en sorte que le cache est correct et la base de données est correcte afin d'éviter les maux de tête. Gérer manuellement signifie que vous aurez le contrôle absolu et vous n'aurez pas à compter sur les cascades de faire votre sale boulot. Dans une seule direction, ils sont fantastiques, la minute où ils viennent "en amont", vous allez avoir certains comportements inattendus.
OriginalL'auteur Daniel B. Chapman
Si vous faites deux objets, et de laisser JPA persistent automatiquement, vous obtiendrez alors deux lignes dans la base de données. Donc, vous avez deux options: ne pas faire de deux objets, ou ne laissez pas la JPA persistent automatiquement.
Pour éviter de faire deux objets, vous devez organiser votre code, de sorte que si les deux Parents essaient de créer des Enfants avec le même nom, ils recevront le même instance réelle. Vous auriez probablement souhaitez un WeakHashMap (dans l'étendue de la demande actuelle, peut-être par le fait d'être visé par des variables locales), identifié par le nom, où les Parents peuvent rechercher leur nouveau nom de l'Enfant pour voir si l'Enfant existe déjà. Si non, ils peuvent créer l'objet et de le mettre dans la carte.
Pour éviter d'avoir JPA persistent les objets automatiquement, chute de la cascade et de l'utilisation persistent à ajouter manuellement les objets du contexte immédiatement après leur création.
Depuis un contexte de persistance est fondamentalement un trompé-out WeakHashMap attaché à une base de données, ces approches sont assez similaires quand il descend à lui.
OriginalL'auteur Tom Anderson
Vous définissez un objet enfant alors si persister le parent, vous êtes le stockage d'un registre dans la base de données qui pointe vers un inexistante enfant.
Lorsque vous créez un nouvel objet, il doit être géré par l'entityManager dans la même manière lorsque vous "trouver" un objet à l'aide de la DAO, on doit obtenir le registre de DB et de mettre l'objet dans l'entityManager contexte.
Essayez d'abord de persister ou de fusion de l'objet enfant.
OriginalL'auteur EricSonaron