Вопрос по hibernate, one-to-many, java-ee, jpa – удаленный объект будет повторно сохранен каскадом (удалить удаленный объект из ассоциаций)

44

у меня есть следующие две сущности:

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: is needed for save and update on the PlaylistadMap collection when saving or updating the playlist entity. orphanRemoval = true: is needed when deleting the playlist entity, the PlaylistadMap references should be deleteed too.

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)

Посоветуйте, пожалуйста, как исправить это исключение.

Ваш Ответ

16   ответов
2

Я смог решить эту проблему, написав код ниже. Я использовал executeUpdate вместо .delete ()

def publicSupport = caseObj?.client?.publicSupport
        if(publicSupport)
            PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
            //publicSupport.delete()
-1
cascade = { CascadeType.ALL }, fetch = FetchType.LAZY
0

если вы удалите с использованием модального PlaylistadMap вместо PlayList. в этом случае FetchType = Lazy - неправильный вариант. Он не будет выдавать никаких исключений, а только данные из PlaylistadMap будут удалены, данные в PlayList останутся в таблице. проверьте это также.

0

FetchType бытьEAGERЯ удаляю все ассоциации, устанавливая их в (null) и сохраняю объект (который удаляет все ассоциации в базе данных), а затем удаляю его!

Это добавляет несколько миллисекунд, но это хорошо для меня, если есть лучший способ сохранить эти MS, добавьте ваш комментарий ниже ...

Надеюсь, что помочь кому-то :)

40

чтобы сделать именно то, что говорит вам сообщение об исключении:

Caused by: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)

Удалите удаленный объект из ассоциаций (наборов, списков или карт), в которых он находится. В частности, я подозреваю, изPlayList.PlaylistadMaps, Недостаточно просто удалить объект, вы должны удалить его из любых каскадных коллекций, которые на него ссылаются.

На самом деле, так как ваша коллекция имеетorphanRemoval = trueВам не нужно явно удалять его. Вам просто нужно удалить его из набора.

В Intellij появилась новая функция под названием «Показывать ссылающиеся объекты». и делает именно так, как он предлагает, я мог бы исправить это, установив ссылку на объект на ноль.
я попытался удалить объект из набора, очистив набор перед удалением следующим образом:playlist.getPlaylistadMaps().clear(); playlist = (Playlist) getCurrentSession().merge(playlist); super.delete(playlist); но это не работает Mahmoud Saleh
Я только что удалил из списка, который cantian объект. это решило мою проблему.
Этот вид работал для меня. У меня было сопоставление OneToOne со ссылочным объектом. ObjectToDelete.getReferencingObject () setObjectToDelete (нуль).
я попытался удалить объект, который будет удален из коллекции перед удалением, как упоминалось здесьstackoverflow.com/questions/3068817/… но он не работает, получая то же исключение Mahmoud Saleh
0

Код, который показывает ошибку:

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

где былаPerson таблица с отношениями one2many сCode стол иOrganization таблица с отношениями one2many с тем жеCode Таблица. Кодекс может применяться как к Организации, так и к Лицу в зависимости от ситуации.Both the Person object and the Organization object were set to Cascade=All delete orphans.

Однако из-за этого перегруженного использования таблицы кодов ни одно лицо, ни организация не могли каскадно удалять, потому что всегда была другая коллекция, на которую была ссылка. Поэтому независимо от того, как он был удален в коде Java из каких-либо ссылок на коллекции или объекты, удаление не удастся. Единственный способ заставить его работать - это удалить его из коллекции, которую я пытался сохранить, затем удалить ее из таблицы кода напрямую, а затем сохранить коллекцию. Таким образом, не было никакой ссылки на это.

0

Этот пост содержит блестящий трюк, чтобы определить, где проблема каскада:
Cascade в то время сCascade.None() до тех пор, пока вы не получите ошибку, а затем вы обнаружили каскад, вызывающий проблему.

Тогда решите проблему либоchanging the original cascade to something else или используяTom Anderson ответ.

5
If you don't know, which collection holds your object

так как я не знал, что такое коллекция, которая содержит ссылку на объект, так что вот способ узнать, какие объекты содержат ссылку на удаленный один: в отладчике вы должны ввести самый низкий уровень стека выполнения до того, как будет сгенерировано исключение, должна быть переменная с именемentityEntryтак что вы получитеPersistenceContext объект из этой переменной:entityEntry.persistenceContext.

Для меняpersistenceContext был примеромStatefulPersistenceContext и эта реализация имеетprivate полеparentsByChild, из которого вы можете получить информацию о коллекции, которая содержит элемент.

Я использовал отладчик Eclipse, поэтому было довольно сложно получить это приватное поле прямым способом, поэтому я использовалDetail Formatter (Как я могу наблюдать частные поля других объектов непосредственно в IDE при отладке?)

После получения этой информации может быть применено решение TomAnderson.

1
Another workaround

Я полностью согласен сredochka а такжеНикос Параскевопулос. Махмуд СалехВ некоторых обстоятельствах ответ на этот вопрос преодолевается не каждый раз. В моей ситуации мне действительно нужен Eager fetchtype. Таким образомкаменистый упомянутое выше Я только что удалил из списка, который может cantian объект тоже. Вот мой код:

Rju entity

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 entity

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

    }
     .........................
}
0

вызванное при попытке удалить ребенка от человека (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, Просто:@ManyToOne на уроке Малыш, и он начал работать, как ожидалось.

Пожалуйста, используйте правильный отступ. Ваш текст не должен быть частью фрагмента кода.
2

Для меня проблема была в другом. Я хотел удалить родителя.

В одной транзакции:

First I called up the parent from the database. Then I called a child element from a collection in the parent. Then I referenced one field in the child (id) Then I deleted the parent. Then I called commit. I got the "deleted object would be resaved" error.

Оказывается, мне пришлось сделать две отдельные транзакции. Я совершил после ссылки на поле в ребенка. Затем начался новый коммит для удаления.

Не было необходимости удалять дочерние элементы или очищать коллекции в родительском элементе (при условииorphanRemoval = true.). Фактически это не сработало.

In sum, this error appears if you have a reference to a field in a child object when that object is being deleted.

1

Вид начала происходит здесь.

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

FetchType вLazy

Hibernate иногда странный.
Вот это да. У меня была проблема в течение нескольких часов, пытаясь использоватьnHibernate сделать связь многих ко многим (с метаданными, используяjoining класс) и в итоге это оказалось моей проблемой тоже. Спасибо!
@Sikorski удалите дочернюю сущность из списка, в котором она содержится, а затем применитеdelete(entity)
@Sikorski - я столкнулся с той же проблемой, но последовал советуhere и это работало нормально для меня.
Есть ли какое-то другое решение, сделать FetchType Lazy действительно не вариант.
1

как все вышеперечисленные решения не работали в спящем режиме 5.2.10.

Но установка карты в нуль, как показано ниже, работает для меня:

playlist.setPlaylistadMaps(null);
0

У меня была такая же проблема. Я пытался удалить и вставить в ту же транзакцию. я добавилtheEntityManager.flush(); послеtheEntityManager.remove(entity);.

Похожие вопросы