java 在 JPA/Hibernate 中删除然后查询失败(已删除的实体传递给持久化)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2938236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:33:10  来源:igfitidea点击:

Remove then Query fails in JPA/Hibernate (deleted entity passed to persist)

javahibernatejpa

提问by Kevin

I've got a problem with the removal of entities in my JPA application: basically, I do in this EJB Business method:

我在删除 JPA 应用程序中的实体时遇到了问题:基本上,我在这个 EJB 业务方法中这样做:

load photo list ;
for each photo {
    //UPDATE
    remove TagPhoto element from @OneToMany relation
    //DISPLAY
    create query involving TagPhoto
    ...
}

and this last query always throws an EntityNotFoundException (deleted entity passed to persist: [...TagPhoto#])

并且最后一个查询总是抛出 EntityNotFoundException (已删除的实体传递给持久化:[...TagPhoto#])

I think I understand the meaning of this exception, like a synchronization problem caused by my Remove, but how can I get rid of it?

我想我明白这个异常的含义,就像我的Remove导致的同步问题,但我怎样才能摆脱它?

EDIT: here is the stack of the exception:

编辑:这是异常的堆栈:

Caused by: javax.persistence.EntityNotFoundException: deleted entity passed to persist: [net.wazari.dao.entity.TagPhoto#<null>]
    at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:621)
    at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:74)
    at net.wazari.dao.jpa.TagFacade.loadVisibleTags(TagFacade.java:108)

and the mapping between Tag-TagPhoto-Photo

以及 Tag-TagPhoto-Photo 之间的映射

public class Tag implements Serializable {
    ...
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "tag")
    private List<TagPhoto> tagPhotoList;
}
public class TagPhoto implements Serializable {
    ...
    @JoinColumn(name = "Tag", referencedColumnName = "ID")
    @ManyToOne(optional = false)
    private Tag tag;
    @JoinColumn(name = "Photo", referencedColumnName = "ID")
    @ManyToOne(optional = false)
    private Photo photo;
}
public class Photo implements Serializable {
    ...
    @OneToMany(cascade = CascadeType.ALL , mappedBy = "photo")
    private List<TagPhoto> tagPhotoList;
}

(it was automatically generated by Netbeans when I created the project)

(它是我创建项目时由 Netbeans 自动生成的)

EDIT: Does it mean that tagPhoto != tagPhoto.getTag().getTagPhotoList().get(...) != tagPhoto.getPhoto().getTagPhotoList().get(...)?

编辑:这是否意味着tagPhoto != tagPhoto.getTag().getTagPhotoList().get(...) != tagPhoto.getPhoto().getTagPhotoList().get(...)

and how shall I remove them? iterator.removeshould not be of any use, and I would think that three em.remove()would do three times the same operation ...

我该如何删除它们?iterator.remove应该没有任何用处,我认为三个em.remove()会做三遍相同的操作......

回答by Pascal Thivent

To be honest, it's hard to say without the mappings (especially the cascading options), without the exact stack trace and without the real code as the pseudo code is very likely not showing the real problem. So this answer is more a shot in the dark (and you should consider posting the mentioned details).

老实说,很难说没有映射(尤其是级联选项),没有确切的堆栈跟踪和真实代码,因为伪代码很可能没有显示真正的问题。所以这个答案更像是在黑暗中拍摄(你应该考虑发布提到的细节)。

My guess is that you're calling remove()on a TagPhotoinstance that you are not removing from the one-to-many association. So when the EntityManagertries to update the parent Photo, it may indeed try to persist a deleted entity, hence the exception.

我的猜测是你正在调用remove()一个TagPhoto你没有从一对多关联中删除的实例。因此,当EntityManager尝试更新父 Photo 时,它可能确实尝试保留已删除的实体,因此出现异常。

Update:You need to remove the TagPhotoinstance from both collections that contain it:

更新:您需要TagPhoto从包含它的两个集合中删除该实例:

photo.getTagPhotoList().remove(tagPhoto);
...
tag.getTagPhotoList().remove(tagPhoto);
...
em.remove(tagPhoto);

Note that things are actually a bit more complicated because NetBeans generated an Entity for the join table (TagPhoto). It would be a bit easier if you had a many-to-many association between Photoand Tag. But in any case, when you remove an entity, you need to remove it from associations, JPA won't do that for you.

请注意,事情实际上有点复杂,因为 NetBeans 为连接表 (TagPhoto) 生成了一个实体。如果您在Photo和之间存在多对多关联,那会容易一些Tag。但无论如何,当您删除一个实体时,您需要将其从关联中删除,JPA 不会为您这样做。

回答by Georg Leber

Might be a problem with the synchronization. Try to call Session.flush()before you create the TagPhoto.

可能是同步问题。Session.flush()在创建 TagPhoto 之前尝试调用。

回答by Hussain Pithawala

I came across almost a similar situation and solved it by simply deleting the references from the owner side.Now in your case TagPhoto is the owner of both the relationships for Tag as well as Photo. All you need to do is query for the TagPhoto from any of the side and remove it and update the reference on the owner side(s).

我遇到了几乎类似的情况,并通过简单地从所有者端删除引用来解决它。现在在您的情况下,TagPhoto 是 Tag 和 Photo 关系的所有者。您需要做的就是从任何一侧查询 TagPhoto 并将其删除并更新所有者侧的引用。

for e.g. in some service which is covered

例如,在某些涵盖的服务中

    for(TagPhoto tagPhoto : photo.getTagPhotoList()){

    boolean update = false;

    for(Iterator<TagPhoto> iterator = 

    tagPhoto.getPhoto().getTagPhotoList().iterator();

    iterator.hasNext();){
            TagPhoto tagPhoto2 = iterator.next();
            if(tagPhoto.getId() == tagPhoto2.getId()){
                iterator.remove();
                update = true;
            }
        }

        if(update){
            tagPhoto.setPhoto(null);
            tagPhoto.setTag(null);
            tagPhotoService.remove(tagPhotoService.update(tagPhoto));
        }
    }

Also make sure you do not call entityManager.flush() explicitly from any of your API(s). It should be called by the transactionManager. Once the transaction completes.

还要确保您没有从任何 API 显式调用 entityManager.flush()。它应该由事务管理器调用。一旦交易完成。