【问题标题】:Deleted object would be re-saved by cascade (remove deleted object from associations)已删除的对象将通过级联重新保存(从关联中删除已删除的对象)
【发布时间】:2012-07-23 20:32:58
【问题描述】:

我有以下两个实体:

1- 播放列表:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "playlist", orphanRemoval = true, cascade =   CascadeType.ALL)
@OrderBy("adOrder")
private Set<PlaylistadMap> PlaylistadMaps = new HashSet<PlaylistadMap>(0);
  • CascadeType.ALL:在保存或更新播放列表实体时需要在 PlaylistadMap 集合上保存和更新。
  • orphanRemoval = true:删除播放列表实体时需要,PlaylistadMap 引用也要删除。

2- 播放列表地图:

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_playlist", referencedColumnName = "pkid", nullable = false)
private Playlist playlist;

当使用getCurrentSession().delete(); 删除播放列表时,出现以下异常:

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)

请告知如何修复此异常。

【问题讨论】:

    标签: hibernate jakarta-ee jpa one-to-many


    【解决方案1】:

    解决方案是完全按照异常消息告诉您的操作:

    原因:org.hibernate.ObjectDeletedException:已删除的对象将被级联重新保存(从关联中删除已删除的对象

    从它所在的关联(集合、列表或映射)中删除已删除的对象。特别是,我怀疑来自PlayList.PlaylistadMaps。仅删除对象是不够的,您必须将其从任何引用它的级联集合中删除。

    事实上,既然你的收藏有orphanRemoval = true,你不需要显式删除它。您只需要将其从集合中移除即可。

    【讨论】:

    • 我试图通过在删除之前清除集合来从集合中删除实体,如下所示:playlist.getPlaylistadMaps().clear(); playlist = (Playlist) getCurrentSession().merge(playlist); super.delete(playlist); 但它不起作用
    • 我试图在删除之前从集合中删除要删除的实体,如此处所述stackoverflow.com/questions/3068817/…,但仍然无法正常工作
    • 我刚刚从列表中删除了该对象。这解决了我的问题。
    • Intellij 有一个名为“显示引用对象”的新功能,并且完全按照它的建议进行操作,我可以通过将对象引用设置为 null 来解决此问题。
    • 这种对我有用。我正在与引用对象进行 OneToOne 映射。 ObjectToDelete.getReferencingObject().setObjectToDelete(null);
    【解决方案2】:

    FetchType 更改为 Lazy

    后问题解决

    【讨论】:

    • Hibernate 有时很奇怪。
    • 哇。我在尝试使用 nHibernate 进行多对多关联(使用 joining 类的元数据)时遇到了一个问题,最后结果是这样也是我的问题。谢谢!
    • 有没有其他的解决办法,让 FetchType Lazy 实在不行。
    • @Sikorski 从包含的列表中删除子实体,然后应用delete(entity)
    • @Sikorski - 我遇到了同样的问题,但遵循了here 的建议,对我来说效果很好。
    【解决方案3】:

    如果你不知道,哪个集合保存你的对象

    在我的情况下,应用 TomAnderson 的解决方案真的很困难,因为我不知道集合是什么,它包含指向对象的链接,所以这里是知道哪些对象包含指向已删除对象的链接的方法:在调试器中你应该在抛出异常之前进入最低的执行堆栈级别,应该有一个名为entityEntry的变量,所以你从这个变量中得到一个PersistenceContext对象:entityEntry.persistenceContext

    对我来说,persistenceContextStatefulPersistenceContext 的一个实例,而这个实现有private 字段parentsByChild,您可以从中检索有关包含该元素的集合的信息。

    我使用的是 Eclipse 调试器,所以很难直接检索这个私有字段,所以我使用了Detail Formatter (How can I watch private fields of other objects directly in the IDE when debugging?)

    得到这些信息后,就可以应用TomAnderson的方案了。

    【讨论】:

      【解决方案4】:

      以上所有解决方案在hibernate 5.2.10.Final中都不起作用。

      但是将地图设置为 null 如下对我有用:

      playlist.setPlaylistadMaps(null);
      

      【讨论】:

        【解决方案5】:

        我也遇到了这个异常消息。 对我来说,问题是不同的。 我想删除一个父级。

        在一笔交易中:

        • 首先我从数据库中调用了父级。
        • 然后我从父集合中调用了一个子元素。
        • 然后我在子项 (id) 中引用了一个字段
        • 然后我删除了父级。
        • 然后我调用了 commit。
        • 我收到“已删除的对象将被重新保存”错误。

        事实证明,我必须进行两次单独的交易。 我在引用子字段后承诺。然后为删除开始一个新的提交。

        无需删除子元素或清空父元素中的集合(假设为orphanRemoval = true.)。事实上,这并没有奏效。

        总之,如果您在删除子对象时引用了子对象中的字段,则会出现此错误。

        【讨论】:

          【解决方案6】:

          我可以通过编写下面的代码来解决这个问题。我使用了 executeUpdate 而不是 .delete()

          def publicSupport = caseObj?.client?.publicSupport
                  if(publicSupport)
                      PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
                      //publicSupport.delete()
          

          【讨论】:

            【解决方案7】:

            这里正在进行某种盗梦空间。

            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);
                        }
                    }
                }
            

            【讨论】:

              【解决方案8】:

              我遇到了同样的问题。我试图在同一个事务中删除和插入。我在theEntityManager.remove(entity); 之后添加了theEntityManager.flush();

              【讨论】:

                【解决方案9】:

                另一种解决方法

                我完全同意redochkaNikos ParaskevopoulosMahmoud Saleh 的回答在某些情况下不是每次都能解决这个问题。在我的情况下,我真的需要 Eager fetchtype。所以正如上面提到的Stony 我刚刚从一个包含该对象的列表中删除。这是我的代码:

                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;
                .........
                }
                

                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..........
                }
                

                还有我的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);
                
                    }
                     .........................
                }
                

                【讨论】:

                  【解决方案10】:

                  因为我需要 FetchTypeEAGER,所以我通过将它们设置为 (null) 来删除所有关联并保存对象(删除数据库中的所有关联)然后删除它!

                  这会增加一些毫秒,但对我来说没问题,如果有更好的方法来保留这些 MS,请在下面添加您的评论..

                  希望对某人有所帮助:)

                  【讨论】:

                    【解决方案11】:

                    我在一个设计糟糕的数据库上也遇到了这个错误,其中有一个 Person 表与 Code 表的 one2many 关系和一个 Organization 表与同一个 Code 表的 one2many 关系.视情况而定,本准则可同时适用于组织或个人。 Person 对象和 Organization 对象都设置为 Cascade=All delete orphans。

                    然而,这种过度使用 Code 表的结果是 Person 和 Organization 都不能级联删除,因为总是有另一个集合引用它。因此,无论它是如何在 Java 代码中从任何引用集合或对象中删除的,删除都会失败。让它工作的唯一方法是将它从我试图保存的集合中删除,然后直接从代码表中删除它,然后保存集合。这样就没有引用它了。

                    【讨论】:

                      【解决方案12】:

                      This post contains a brilliant trick to detect where the cascade problem is:
                      尝试将 Cascade 上的替换为 Cascade.None(),直到您没有收到错误,然后您检测到导致问题的级联。

                      然后通过将原始级联更改为其他方式或使用Tom Anderson答案来解决问题。

                      【讨论】:

                        【解决方案13】:

                        我有同样的例外,当试图从人身上移除孩子时(Person - OneToMany - Kid)。 在人方面注释:

                        @OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, ... cascade    = CascadeType.ALL)
                        public Set<Kid> getKids() {    return kids; }
                        

                        Kid 侧注释:

                        @ManyToOne(cascade = CascadeType.ALL)
                        @JoinColumn(name = "person_id")
                        public Person getPerson() {        return person;    }
                        

                        所以解决方案是删除 cascade = CascadeType.ALL,很简单:@ManyToOne 在 Kid 类上,它开始按预期工作。

                        【讨论】:

                        • 请使用正确的缩进。您的文本不应包含在代码 sn-p 中。
                        【解决方案14】:

                        有同样的错误。从模型中移除对象就可以了。

                        显示错误的代码:

                        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();
                        }
                        

                        【讨论】:

                          【解决方案15】:

                          我只是为了解决这个问题。

                          1. 我将列表的值设置为null
                          2. 我保存了对象(有效)
                          3. 我给对象设置了新数据
                          4. 我重新保存了对象
                          5. 有效!

                          【讨论】:

                            【解决方案16】:

                            您需要删除映射对象上的关联:

                            playList.getPlaylistadMaps().setPlayList(null);
                            session.delete(playList);
                            

                            【讨论】:

                              【解决方案17】:

                              解决方法是“破坏”对象之间的关系,然后再次尝试删除。 答案在您的日志中:

                              (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]
                              

                              解释:什么?(删除关联)在哪里?[ID#6 的PlaylistadMap 对象]

                              【讨论】:

                                【解决方案18】:

                                如果您使用PlaylistadMap 模态而不是PlayList 进行删除,则会出现此问题。在这种情况下,FetchType = Lazy 不是正确的选择。它不会抛出任何异常,但只会删除来自PlaylistadMap 的数据,PlayList 中的数据将保留在表中。也检查一下。

                                【讨论】:

                                  【解决方案19】:
                                  cascade = { CascadeType.ALL }, fetch = FetchType.LAZY
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2011-08-26
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2013-10-03
                                    • 2019-06-30
                                    • 1970-01-01
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多