Я использую JPA с Hibernate внизу, и у меня возникают проблемы с тем, чтобы слияние работало, но прежде чем я опишу проблемы, с которыми я сталкиваюсь при использовании JPA, позвольте мне изложить, что я пытаюсь выполнить, на случай, если мои проблемы связаны с моим подходом. .
У меня есть данные из системы, которые мне нужно поместить в другую систему. Для этого я читаю данные, затем создаю новые объекты ORM на основе этих данных, а затем хочу сохранить объекты ORM в базе данных. Теперь, когда база данных пуста, программа работает без проблем с простым вызовом em.persist(object). Однако я хочу иметь возможность запускать этот процесс, когда в базе данных есть данные, добавляя новые данные и обновляя старые данные по мере необходимости, вот где у меня возникают проблемы.
Я делаю простую проверку, чтобы убедиться, что элемент уже существует в базе данных, если ничего не найдено, я сохраняюсь, если запись существует, я пытаюсь выполнить слияние. Который терпит неудачу с дублирующей ошибкой записи;
ERROR JDBCExceptionReporter - Violation of UNIQUE KEY constraint 'UK-SubStuff-StuffId-SubStuffNumber'. Cannot insert duplicate key in object 'SubStuff'.
Мне кажется странным, что вызов em.merge() пытается вставить вместо обновления (я подтвердил это с помощью журнала SQL).
Hibernate: insert into SubStuff (SubStuffNumber, StuffId, Name, TypeId) values (?, ?, ?, ?)
Я должен отметить, что я использую объекты, которые каскадируются в подобъекты. Сбой происходит на подобъекте, что имеет смысл для меня, поскольку я ожидаю, что он сначала попытается объединить подобъекты.
Ниже приведен мой код, извините за грубое состояние, я попытался задокументировать здесь несколько обходных путей.
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);
}
}
}
Если кто-нибудь с опытом JPA может мне помочь, я был бы очень признателен. Различия между saveOrUpdate() в Hibernate и merge() в JPA явно сбивают меня с толку, но, несмотря на то, что я прочитал несколько статей о слиянии EnityManger, я до сих пор не могу понять, что здесь происходит.
Спасибо за ваше время.