web-dev-qa-db-ja.com

削除されたオブジェクトはカスケードによって再保存されます(削除されたオブジェクトを関連付けから削除します)

次の2つのエンティティがあります。

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- PlaylistadMap:

_@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)
_

この例外を修正する方法を教えてください。

45
Mahmoud Saleh

FetchTypeLazyに変更した後に解決した問題

21
Mahmoud Saleh

解決策は、例外メッセージが示す内容を正確に実行することです。

原因:org.hibernate.ObjectDeletedException:削除されたオブジェクトはカスケードによって再保存されます(関連付けから削除されたオブジェクトを削除

削除されたオブジェクトを、それが属する関連付け(セット、リスト、またはマップ)から削除します。特に、PlayList.PlaylistadMaps。オブジェクトを単に削除するだけでは十分ではありません。オブジェクトを参照するカスケードコレクションから削除する必要があります。

実際、コレクションにはorphanRemoval = true、明示的に削除する必要はありません。セットから削除するだけです。

43
Tom Anderson

わからない場合は、どのコレクションがオブジェクトを保持しているか

私の場合、TomAndersonのソリューションを適用するのは非常に困難でした。コレクションとは何か、オブジェクトへのリンクを保持しているかわからなかったので、ここでは、削除されたオブジェクトへのリンクを保持しているオブジェクトを知る方法があります:デバッガーは、例外がスローされる前に最低の実行スタックレベルに入る必要があります。entityEntryという変数があるはずです。そのため、この変数からPersistenceContextオブジェクトを取得します:entityEntry.persistenceContext

私にとってpersistenceContextStatefulPersistenceContextのインスタンスであり、この実装にはprivateフィールドparentsByChildがあります。このフィールドから、要素を含むコレクションに関する情報を取得できます。

私はEclipseデバッガを使用していたので、このプライベートフィールドをまっすぐに取得するのはちょっと難しいので、Detail Formatterを使用しました( 他のオブジェクトのプライベートフィールドをIDEデバッグ時?

この情報を取得した後、TomAndersonのソリューションを適用できます。

5
Dmitry Ginzburg

以下のコードを書くことでこれを解決できました。 .delete()の代わりにexecuteUpdateを使用しました

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

上記のすべてのソリューションがhibernate 5.2.10.Finalで機能しなかった方法。

しかし、以下のようにマップをnullに設定するとうまくいきました:

playlist.setPlaylistadMaps(null);
2
KayV

この例外メッセージも発生しました。私にとって問題は異なっていました。親を削除したかった。

1つのトランザクションで:

  • まず、データベースから親を呼び出しました。
  • 次に、親のコレクションから子要素を呼び出しました。
  • 次に、子(id)の1つのフィールドを参照しました
  • その後、親を削除しました。
  • 次に、コミットを呼び出しました。
  • 「削除されたオブジェクトは再保存されます」というエラーが表示されました。

私は2つの別々のトランザクションをしなければならなかったことがわかりました。子のフィールドを参照した後、コミットしました。次に、削除のための新しいコミットを開始しました。

子要素を削除したり、親のコレクションを空にする必要はありませんでした(orphanRemoval = true。)。実際、これは機能しませんでした。

要するに、このエラーは、そのオブジェクトが削除されているときに子オブジェクトのフィールドへの参照がある場合に表示されます。

2
Jake

ここで起こっているインセプションの種類。

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);
            }
        }
    }
1
Ben Tennyson

別の回避策

redochka および Nikos Paraskevopoulos に完全に同意します。 Mahmoud 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..........
}

and myUnderrjuService

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

    }
     .........................
}
1
Frank

FetchType[〜#〜] eager [〜#〜]にする必要があるため、すべての関連付けを(null)に設定して削除し、オブジェクトを(削除する)データベース内のすべての関連付け)削除します!

それは数ミリ秒を追加しますが、それらのMSにコメントを追加するより良い方法があれば、私にとっては問題ありません。

誰かを助けることを願っています:)

0
Smile2Life

この問題は、PlayListの代わりにPlaylistadMapモーダルを使用して削除した場合に発生します。この場合、FetchType = Lazyは適切なオプションではありません。例外はスローされませんが、PlaylistadMapのデータのみが削除され、PlayListのデータはテーブルに残ります。それも確認してください。

0
RAGINROSE

私は同じ例外を持っていた、人から子供を削除しようとしたときに引き起こされた(Person-OneToMany-Kid)。人の側の注釈:

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

子供側の注釈について:

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

そのため、解決策はcascade = CascadeType.ALLを削除することで、Kidクラスの@ManyToOneを削除するだけで、期待どおりに機能し始めました。

0
Oleh Podolyan

また、設計が不適切なデータベースでこのエラーに遭遇し、Personテーブルとのone2many関係を持つCodeテーブルと、one2many関係を持つOrganizationテーブルがありました同じCodeテーブル。コードは、状況に応じて組織と個人の両方に適用できます。 PersonオブジェクトとOrganizationオブジェクトの両方がCascade = All delete orphansに設定されていました。

ただし、コードテーブルのこのオーバーロードされた使用からは、PersonもOrganizationも参照を保持する別のコレクションが常に存在するため、カスケード削除できませんでした。したがって、どのコレクションを参照するコレクションやオブジェクトからJavaコードを削除しても、削除は失敗します。それを機能させる唯一の方法は、コレクションから削除することでした。保存してからCodeテーブルから直接削除してからコレクションを保存しようとすると、その参照はありませんでした。

0
Uncle Iroh

同じエラーがありました。モデルからオブジェクトを削除するのがうまくいきました。

間違いを示すコード:

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

私は同じ問題を抱えていました。同じトランザクションで削除と挿入を試みました。 theEntityManager.flush();の後にtheEntityManager.remove(entity);を追加しました。

0
Jai

この投稿には、カスケードの問題がどこにあるかを検出するための素晴らしいトリックが含まれています:
エラーが発生せず、問題の原因となっているカスケードを検出するまで、CascadeCascade.None()に置き換えてみてください。 。

次に、元のカスケードを他のカスケードに変更するか、Tom Anderson回答を使用して問題を解決します。

0