2014-10-13 1 views
5

Я пытаюсь удалить сущность, которая связана с различными отношениями (только @ManyToOne). Однако Hibernate ничего не удаляет - после вызова em.remove все остается неизменным.Hibernate EntityManager: удалить ссылочный объект не работает


У меня есть 5 объектов (E1 - E5), ссылки на объекте (E6) в вопросе, как это:

@Entity 
public class EX { 
    @OneToMany(mappedBy = "eX", fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.REMOVE }) 
    private Set<E6> e6s; 
} 

E6 сами имеют реверс @ManyToOne отношений:

public class E6{ 

    @ManyToOne(optional = false) 
    private E1 e1;  

    @ManyToOne(optional = false) 
    private E2 e2; 

    @ManyToOne(optional = false) 
    private E3 e3; 

    @ManyToOne(optional = false) 
    private E4 e4; 

    @ManyToOne(optional = false) 
    private E5 e5; 
} 

(слева выходы, дополнительные столбцы и т. д.)


Всякий раз, когда я звоню em.remove(instanceOfE6), просто ничего не происходит. Я добавил Hibernate SQL-Output и не вижу ни одной попытки выполнить запрос DELETE.

Поскольку удаление может происходить из АЯКС запроса и свежей EntityManager, я добавил вызов сливаться перед удалением, вызвать otherwhise я получаю Entity неуправляемого Exception:

em.remove(em.merge(instanceOfE6)); 

Но ничего , Государство остается без изменений.

Поэтому я попытался добавить метод @PreRemove, чтобы очистить все отношения до удаления объекта ... Метод никогда не вызывается.

Я пробовал различные операции с каскадом (включая Cascade.ALL) - но поскольку все, что мне нужно, это удалить и сохранить, это тоже должно работать.


Я думал об использовании родного ВЕЬЕТЕ (каждый субъект имеет суррогатный идентификатор, так что, скорее всего, работа) - но так как все происходит изнутри AJAX-вызов, я не хочу использовать это , потому что я хочу обновить кэш-память с сохранением без повторной выборки всех вовлеченных объектов ...

Любые идеи?

Если вам нужно больше источника, просто напишите мне комментарий.


Я также попытался удалить объект в вопросе от ВСЕХ отношений (объект мудры), и вызвать em.merge() на одном из оставшихся лиц, в надежде, что спящий режим будет whipe на несвязанный объект - не повезло.

+1

Вы совершили транзакцию? –

+0

Вы назвали 'em.flush()'? – jmvivo

+0

@DavidLevesque Запуск Hibernate в режиме autocommit ... – dognose

ответ

13

я понял проблему (ы) - Актуальный было два из них: (Оставляя это здесь, если кто-то натыкается на аналогичный вопрос)

Как я уже говорил, удаление должно было произойти в AJAX запрос. Поэтому простой вызов

em.remove(instanceOfE6); 

привело к исключению java.lang.IllegalArgumentException: Removing a detached instance.Итак, я попытался использовать метод слияния:

em.remove(em.merge(instanceOfE6)); 

который не выдал ошибку - но прост не работал. Я позволил проследить каротаж для спящего режима, как указано в этом сообщении: JPA/Hibernate remove entity sometimes not working, чтобы выяснить, что пошло не так, и в самом деле, пытаясь удалить объект в результате:

TRACE [org...DefaultPersistEventListener] un-scheduling entity deletion ... 

Очевидно, что лица, чтобы удалить все еще подключен к другим лицам , которые приводят к проблеме, из-за которой hibernate прерывает удаление, поэтому я попытался удалить отношения перед удалением. Как видно из примера E6, я использовал @ManyToOne(optional = false), что означает, что я не могу установить исходящие ссылки на нуль, иначе это вызовет исключения при вызове merge.

Моя первая попытка очистить отношения была только «очистка наборов», поскольку я предполагал, что очистка исходящих отношений объекта, который я хочу удалить, не требуется. Это не так, но я обрисую в общих чертах это подробно чуть позже:

Таким образом, код в настоящее время выглядел как

instanceOfE6.getE1().getE6s().remove(instanceOfE6); 
instanceOfE6.getE2().getE6s().remove(instanceOfE6); 
instanceOfE6.getE3().getE6s().remove(instanceOfE6); 
instanceOfE6.getE4().getE6s().remove(instanceOfE6); 
instanceOfE6.getE5().getE6s().remove(instanceOfE6); 

em.remove(em.merge(instanceOfE6)); 

Та же проблема: удаление прервана. Я пропустил очевидный факт, что вызов merge будет из cc. восстановить записи внутри наборов, которые я только что удалил, , потому что экземплярOfE6 STILL не имел ссылок на NULL для других объектов. Поэтому удаление было отменено снова.

И наконец решение c. было сделать слияние перед удалением ссылки и окончательное удаление:

if (!em.contains(instanceOfE6)){ 
    instanceOfE6 = em.merge(instanceOfE6); 
} 

instanceOfE6.getE1().getE6s().remove(instanceOfE6); 
instanceOfE6.getE2().getE6s().remove(instanceOfE6); 
instanceOfE6.getE3().getE6s().remove(instanceOfE6); 
instanceOfE6.getE4().getE6s().remove(instanceOfE6); 
instanceOfE6.getE5().getE6s().remove(instanceOfE6); 

em.remove(instanceOfE6); 

Я не совсем уверен, что если бы я объяснил все 100% точно, но, по крайней мере, я могу воспроизвести и исправить проблему, изменение кода взад и вперед.

+2

Ты спасатель. Они боролись с этим один в течение двух часов. Большое вам спасибо. Люди, следите за деревьями сущностей (мне пришлось написать groupToRemove.getParent(). GetSubgroups(). Remove (groupToRemove) и пришлось сопоставить родительский с cascade = CascadeType.MERGE). Cheers – jpangamarca

+1

'groupToRemove.getParent(). GetSubgroups(). Remove (groupToRemov e)' именно это я и сделал. Это выглядит странно ... но вдаваясь в это: это логично :-) – dognose