Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot remove entity which is target of @OneToOne relation

I have following entities with @OneToOne relation:

@Entity
public static class EntityChild extends BaseEntity {
    //Id from superclass
}

@Entity
public static class EntityParent extends BaseEntity {

    //Id from superclass

    @OneToOne(cascade = ALL)
    private EntityChild child;

    //child getter/setter
}

Now following test doesn't pass:

EntityParent parent = new EntityParent();
em.persist(parent);
em.flush();

EntityChild child = new EntityChild();
parent.setChild(child);
em.persist(parent);
em.flush();

em.remove(parent.getChild());
em.flush();

It throws exception on the last line, with flush(). The exception is javax.persistence.EntityNotFoundException: deleted entity passed to persist: [my.package.EntityChild#<null>]

Why can't I delete this entity?

like image 475
amorfis Avatar asked Jan 20 '11 14:01

amorfis


1 Answers

You need to remove the association between parent and child first, otherwise Hibernate tries to persist the child again due to cascade = ALL:

EntityChild c = parent.getChild();
parent.setChild(null);
em.remove(c);
em.flush(); 

Update:

Here are excerpts from the JPA specification related to this behaviour. Exception is thrown due to conflict between [1] and [2] during flush() (though I can't find where it's specified):

The semantics of the flush operation, applied to an entity X are as follows:

  • If X is a managed entity, it is synchronized to the database.

    • For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y.

    • For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade element value cascade=PERSIST or cascade= ALL:

      • If Y is new or removed, an IllegalStateException will be thrown by the flush operation (and the transaction marked for rollback) or the transaction commit will fail.

      • If Y is detached, the semantics depend upon the ownership of the relationship. If X owns the relationship, any changes to the relationship are synchronized with the database; otherwise, if Y owns the relationships, the behavior is undefined.

  • If X is a removed entity, it is removed from the database. No cascade options are relevant. <--------------- [1]


The semantics of the persist operation, applied to an entity X are as follows:

  • If X is a new entity, it becomes managed. The entity X will be entered into the database at or before transaction commit or as a result of the flush operation.

  • If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are annotated with the cascade=PERSIST or cascade=ALL annotation element value or specified with the equivalent XML descriptor element.

  • If X is a removed entity, it becomes managed. <--------------- [2]

  • If X is a detached object, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time.

  • For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y.

like image 109
axtavt Avatar answered Sep 30 '22 05:09

axtavt