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

时间:2010-05-30 10:36:31

标签: java hibernate jpa

我在删除JPA应用程序中的实体方面遇到了问题:基本上,我使用此EJB Business方法:

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

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

我想我理解这个异常的含义,比如我的Remove引起的同步问题,但是我怎么能摆脱它呢?

编辑:这是异常的堆栈:

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)

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

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

编辑:这是tagPhoto != tagPhoto.getTag().getTagPhotoList().get(...) != tagPhoto.getPhoto().getTagPhotoList().get(...)吗?

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

3 个答案:

答案 0 :(得分:7)

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

我的猜测是,您在remove()实例上调用TagPhoto,而您没有从一对多关联中删除。因此,当EntityManager尝试更新父Photo时,它可能确实会尝试保留已删除的实体,因此例外。

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

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

例如在一些涵盖的服务中

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

另外,请确保不要从任何API中明确调用entityManager.flush()。它应该由transactionManager调用。交易完成后。