I've got a problem with the removal of entities in my JPA application: basically, I do in this EJB Business method:
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#])
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?
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(Abstr开发者_运维技巧actEntityManagerImpl.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
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)
EDIT: Does it mean that tagPhoto != tagPhoto.getTag().getTagPhotoList().get(...) != tagPhoto.getPhoto().getTagPhotoList().get(...)
?
and how shall I remove them? iterator.remove
should not be of any use, and I would think that three em.remove()
would do three times the same operation ...
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 TagPhoto
instance that you are not removing from the one-to-many association. So when the EntityManager
tries to update the parent Photo, it may indeed try to persist a deleted entity, hence the exception.
Update: You need to remove the TagPhoto
instance from both collections that contain it:
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 Photo
and Tag
. But in any case, when you remove an entity, you need to remove it from associations, JPA won't do that for you.
Might be a problem with the synchronization.
Try to call Session.flush()
before you create the TagPhoto.
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).
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.
精彩评论