hibernate - delete - el objeto eliminado se volvería a guardar por cascada(eliminar el objeto eliminado de las asociaciones)
delete hibernate (15)
Si no sabes, qué colección tiene tu objeto
En mi caso, fue muy difícil aplicar la solución de TomAnderson, ya que no sabía qué es la colección, que contiene un enlace a un objeto, así que aquí está la manera de saber qué objetos contienen el enlace al eliminado: en el entityEntry
ingresar el nivel más bajo de la pila de ejecución antes de lanzar la excepción, debe haber una variable llamada entityEntry
, por lo que obtienes un objeto PersistenceContext
de esta variable: entityEntry.persistenceContext
.
Para mí persistenceContext
era una instancia de StatefulPersistenceContext
y esta implementación tiene private
campo private
parentsByChild
, desde el que puede recuperar información sobre la colección, que contiene el elemento.
Estaba usando el depurador Eclipse, por lo que era un poco difícil recuperar este campo privado de forma directa, así que utilicé Detail Formatter
( ¿Cómo puedo ver campos privados de otros objetos directamente en el IDE al depurar? )
Después de obtener esta información, se puede aplicar la solución de TomAnderson.
Tengo las siguientes dos entidades:
1- PlayList:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "playlist", orphanRemoval = true, cascade = CascadeType.ALL)
@OrderBy("adOrder")
private Set<PlaylistadMap> PlaylistadMaps = new HashSet<PlaylistadMap>(0);
- CascadeType.ALL : es necesario para guardar y actualizar en la colección PlaylistadMap al guardar o actualizar la entidad de la lista de reproducción.
- orphanRemoval = true : es necesario al eliminar la entidad de la lista de reproducción, las referencias de PlaylistadMap también deben eliminarse.
2- PlaylistadMapa:
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_playlist", referencedColumnName = "pkid", nullable = false)
private Playlist playlist;
al eliminar una lista de reproducción usando getCurrentSession().delete();
recibo la siguiente excepción:
org.springframework.dao.InvalidDataAccessApiUsageException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]; nested exception is org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:657)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy54.deletePlayList(Unknown Source)
at com.xeno.advertisingsuite.web.beans.PlayListBean.deletePlaylist(PlayListBean.java:282)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.el.parser.AstValue.invoke(AstValue.java:262)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
... 103 more
Caused by: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]
at org.hibernate.impl.SessionImpl.forceFlush(SessionImpl.java:1220)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:188)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
por favor asesórese sobre cómo solucionar esta excepción.
Otra solución
Estoy completamente de acuerdo con redochka y Nikos Paraskevopoulos . La respuesta de supera el problema en algunas circunstancias, no siempre. En mi situación, realmente necesito Eager fetchtype. Entonces, como Stony mencionó anteriormente, simplemente eliminé de una lista que cantian el objeto también. Aquí está mi código:
Entidad Rju
public class Rju extends AbstractCompany implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4294142403795421252L;
//this field just duplicates @Column(name="callname") and serves for mapping to Rju fullname field
@Column(name = "fullname")
private String namerju;
@NotEmpty
@Column(name = "briefname")
private String briefname;
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "otd")
private Collection<Vstan> vStanCollection;
// @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "rju", orphanRemoval = true)
private Collection<Underrju> underRjuCollection;
.........
}
Entidad Underrju
public class Underrju extends AbstractCompany implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2026147847398903848L;
@Column(name = "name")
private String name;
@NotNull
@Valid
@JoinColumn(name = "id_rju", referencedColumnName = "id")
@ManyToOne(optional = false)
private Rju rju;
......getters and setters..........
}
y mi UnderrjuService
@Service("underrjuService")
@Transactional
public class UnderRjuServiceImpl implements UnderRjuService {
@Autowired
private UnderRjuDao underrjuDao;
.............another methods........................
@Override
public void deleteUnderrjuById(int id) {
Underrju underrju=underrjuDao.findById(id);
Collection<Underrju> underrjulist=underrju.getRju().getUnderRjuCollection();
if(underrjulist.contains(underrju)) {
underrjulist.remove(underrju);
}
underrjuDao.delete(id);
}
.........................
}
Como necesito que FetchType sea EAGER , elimino todas las asociaciones estableciéndolas en (nulo) y guardo el objeto (que elimina todas las asociaciones en la base de datos) y luego lo elimino.
Eso agrega algunos milisegundos pero está bien para mí, si hay una mejor manera de que esos MS agreguen tu comentario a continuación ...
Espero que ayudes a alguien :)
De alguna forma, todas las soluciones anteriores no funcionaron en hibernación 5.2.10.Final.
Pero establecer el mapa en nulo como a continuación funcionó para mí:
playlist.setPlaylistadMaps(null);
Encontré este mensaje de excepción también. Para mí, el problema era diferente. Yo quería eliminar un padre
En una transacción: Primero llamé al padre de la base de datos. Luego llamé a un elemento hijo de una colección en el padre. Luego hice referencia a un campo en el elemento secundario (id) Luego eliminé el elemento primario. Entonces llamé a commit. Obtuve el error "se borró el objeto eliminado".
Resulta que tuve que hacer dos transacciones por separado. Me comprometí después de hacer referencia al campo en el niño. Luego comenzó una nueva confirmación para la eliminación.
No hubo necesidad de eliminar los elementos secundarios o vaciar las colecciones en el elemento principal (suponiendo que huérfanoRemoval = verdadero). De hecho, esto no funcionó.
En resumen, este error aparece si tiene una referencia a un campo en un objeto hijo cuando ese objeto se está eliminando.
Estaba teniendo el mismo problema. Estaba intentando eliminar e insertar en la misma transacción. theEntityManager.flush();
después theEntityManager.remove(entity);
.
La solución es hacer exactamente lo que el mensaje de excepción te dice:
Causado por: org.hibernate.ObjectDeletedException: el objeto eliminado se volvería a guardar por cascada ( eliminar el objeto eliminado de las asociaciones )
Elimine el objeto eliminado de una asociación (conjuntos, listas o mapas) en el que se encuentra. En particular, sospecho, de PlayList.PlaylistadMaps
. No basta con eliminar el objeto, debe eliminarlo de las colecciones en cascada que se refieren a él.
De hecho, como su colección tiene orphanRemoval = true
, no necesita eliminarla explícitamente. Solo necesita eliminarlo del conjunto.
Pude resolver esto escribiendo el código a continuación. Usé executeUpdate en lugar de .delete ()
def publicSupport = caseObj?.client?.publicSupport
if(publicSupport)
PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
//publicSupport.delete()
También encontré este error en una base de datos mal diseñada, donde había una tabla Person
con una relación one2many con una tabla Code
y una tabla Organization
con una relación one2many con la misma tabla Code
. El Código podría aplicarse tanto a una Organización como a una Persona dependiendo de la situación. Tanto el objeto Person como el objeto Organization se configuraron en Cascade = All delete huérfanos.
Sin embargo, lo que sucedió con este uso sobrecargado de la tabla de códigos fue que ni la persona ni la organización podían eliminar en cascada porque siempre había otra colección que tenía una referencia a ella. Así que no importa cómo se eliminó en el código de Java de lo que hace referencia a colecciones u objetos, la eliminación fallaría. La única forma de hacerlo funcionar era eliminarlo de la colección que estaba tratando de guardar, luego eliminarlo de la tabla de Código directamente y luego guardar la colección. De esa manera no había referencia a eso.
Tenía el mismo error. Eliminar el objeto del modelo fue el truco.
Código que muestra el error:
void update() {
VBox vBox = mHboxEventSelection.getVboxSelectionRows();
Session session = HibernateUtilEventsCreate.getSessionFactory().openSession();
session.beginTransaction();
HashMap<String, EventLink> existingEventLinks = new HashMap<>();
for (EventLink eventLink : mEventProperty.getEventLinks()) {
existingEventLinks.put(eventLink.getEvent().getName(), eventLink);
}
mEventProperty.setName(getName());
for (Node node : vBox.getChildren()) {
if (node instanceof HBox) {
JFXComboBox<EventEntity> comboBoxEvents = (JFXComboBox<EventEntity>) ((HBox) node).getChildren().get(0);
if (comboBoxEvents.getSelectionModel().getSelectedIndex() == -1) {
Log.w(TAG, "update: Invalid eventEntity collection");
}
EventEntity eventEntity = comboBoxEvents.getSelectionModel().getSelectedItem();
Log.v(TAG, "update(" + mCostType + "): event-id=" + eventEntity.getId() + " - " + eventEntity.getName());
String split = ((JFXTextField) (((HBox) node).getChildren().get(1))).getText();
if (split.isEmpty()) {
split = "0";
}
if (existingEventLinks.containsKey(eventEntity.getName())) {
// event-link did exist
EventLink eventLink = existingEventLinks.get(eventEntity.getName());
eventLink.setSplit(Integer.parseInt(split));
session.update(eventLink);
existingEventLinks.remove(eventEntity.getName(), eventLink);
} else {
// event-link is a new one, so create!
EventLink link1 = new EventLink();
link1.setProperty(mEventProperty);
link1.setEvent(eventEntity);
link1.setCreationTime(new Date(System.currentTimeMillis()));
link1.setSplit(Integer.parseInt(split));
eventEntity.getEventLinks().add(link1);
session.saveOrUpdate(eventEntity);
}
}
}
for (Map.Entry<String, EventLink> entry : existingEventLinks.entrySet()) {
Log.i(TAG, "update: will delete link=" + entry.getKey());
EventLink val = entry.getValue();
mEventProperty.getEventLinks().remove(val); // <- remove from model
session.delete(val);
}
session.saveOrUpdate(mEventProperty);
session.getTransaction().commit();
session.close();
}
Tipo de inicio pasando aquí.
for (PlaylistadMap playlistadMap : playlistadMaps) {
PlayList innerPlayList = playlistadMap.getPlayList();
for (Iterator<PlaylistadMap> iterator = innerPlayList.getPlaylistadMaps().iterator(); iterator.hasNext();) {
PlaylistadMap innerPlaylistadMap = iterator.next();
if (innerPlaylistadMap.equals(PlaylistadMap)) {
iterator.remove();
session.delete(innerPlaylistadMap);
}
}
}
Tuve la misma excepción, causada al intentar eliminar al niño de la persona (Persona - OneToMany - Kid). Anotación del lado de la persona:
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, ... cascade = CascadeType.ALL)
public Set<Kid> getKids() { return kids; }
En la anotación del lado del niño:
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "person_id")
public Person getPerson() { return person; }
Entonces la solución fue eliminar cascade = CascadeType.ALL
, simplemente simple: @ManyToOne
en la clase Kid y comenzó a funcionar como se esperaba.
problema resuelto después de cambiar el FetchType a Lazy
Esta publicación contiene un truco brillante para detectar dónde está el problema de la cascada:
Intente reemplazarlo en Cascade en ese momento con Cascade.None()
hasta que no obtenga el error y luego haya detectado la cascada que causa el problema.
Luego resuelva el problema cambiando la cascada original a otra cosa o usando la respuesta de Tom Anderson .
cascade = { CascadeType.ALL }, fetch = FetchType.LAZY