J'utilise JPA avec Hibernate en dessous, et j'ai du mal à faire fonctionner la fusion, mais avant de décrire les problèmes que je rencontre avec JPA, permettez-moi d'exposer ce que j'essaie d'accomplir, au cas où mes problèmes de mon approche.JPA EntityManger préformant une insertion de base de données lors de la fusion?
J'ai des données sur le système que j'ai besoin de placer dans un autre système. Pour ce faire, je suis en train de lire les données puis de construire de nouveaux objets ORM en fonction de ces données, je veux ensuite conserver les objets ORM dans la base de données. Maintenant, lorsque la base de données est vide, le programme fonctionne sans problème, avec un simple appel em.persist (objet). Cependant, je veux être en mesure d'exécuter ce processus lorsque la base de données contient des données, en ajoutant de nouvelles données et en mettant à jour les anciennes données si nécessaire, c'est là que j'ai des problèmes.
Je fais une vérification simple pour voir si l'élément existe déjà dans la base de données, si rien n'est trouvé, je persiste, si l'enregistrement existe, je tente une fusion. Qui échoue avec une erreur d'enregistrement en double;
ERROR JDBCExceptionReporter - Violation of UNIQUE KEY constraint 'UK-SubStuff-StuffId-SubStuffNumber'. Cannot insert duplicate key in object 'SubStuff'.
Il me semble étrange que l'appel em.merge() tente un insert au lieu d'une mise à jour (je confirme cela par la journalisation SQL).
Hibernate: insert into SubStuff (SubStuffNumber, StuffId, Name, TypeId) values (?, ?, ?, ?)
Je devrais noter que j'utilise des objets qui cascadent dans des sous-objets. L'échec se produit sur un sous-objet, ce qui est logique pour moi car je m'attendrais à essayer de fusionner les sous-objets en premier. Ci-dessous est mon code, s'il vous plaît excusez l'état approximatif, j'ai essayé de documenter quelques approches de contournement ici.
private void storeData(Collection<Stuff> Stuffs) {
for (Stuff stuff : Stuffs) {
//I think this first block can be safely ignored, as I am having no issues with it
// Left it in just in case someone more experianced then I sees the root of the issue here.
Collection<SubStuff> subStuffs = stuff.getSubStuffCollection();
for (SubStuff s : subStuffs) {
//Persist SubStuff Type, which DOES NOT cascade,
// due to it not having an internal SubStuff collection
Query q = em.createNamedQuery("SubStuffType.findByType");
q.setParameter("type", f.getTypeId().getType());
try {
SubStuffType sst = (SubStuffType) q.getSingleResult();
s.setTypeId(sst);
} catch (NoResultException ex) {
if (logger.isDebugEnabled()) logger.debug("SubStuff Type not found, persisting");
em.persist(s.getTypeId());
}
}
if (em.find(Stuff.class, stuff.getId()) == null) {
//Persist on Stuffs will cascade to SubStuffs
em.persist(stuff);
} else {
// Failing to merge SubStuff, tries to insert duplicate
// Merge SubStuff first
// The block below is my attempt to merge the SubStuff Collection before merging Stuff,
// it creates the same isuse as a straight merge of Stuff.
Collection<SubStuff> mergedSubStuffs = new ArrayList<SubStuff>(SubStuffs.size());
for (SubStuff s : SubStuffs) {
Query q = em.createNamedQuery("SubStuff.findBySubStuffNumberStuffId");
q.setParameter("SubStuffNumber", s.getSubStuffNumber());
q.setParameter("StuffId", stuff.getId());
try {
SubStuff subStuff = (SubStuff) q.getSingleResult();
// -----> Merge fails, with an duplicate insert error
SubStuff mergedSubStuff = em.merge(s);
mergedSubStuffs.add(mergedSubStuff);
} catch (NoResultException ex) {
throw ex;
}
}
stuff.setSubStuffCollection(mergedSubStuffs);
// -----> This will fails with same error as above, if I remove the attempt
// to merge the sub objects
em.merge(stuff);
}
}
}
Si quelqu'un ayant une expérience JPA peut m'aider, je l'apprécierais vraiment. Les différences entre saveOrUpdate() de Hibernate et merge() de JPA me font évidemment trébucher, mais malgré la lecture de plusieurs articles sur la fusion d'EnityManger, je ne peux toujours pas comprendre ce qui se passe ici.
Merci pour votre temps.
Pouvez-vous publier comment vous avez mappé l'association de 'stuff' à 'subStuffCollection'? – zmf
Stuff est un à plusieurs à sous-soumettre. L'annotation est @OneToMany (cascade = CascadeType.ALL, mappedBy = "stuffId", fetch = FetchType.LAZY). –