Deleted entity passed to persist - Hibernate or Play bug

666 views
Skip to first unread message

Daniel Guryca

unread,
Jan 22, 2010, 4:46:13 AM1/22/10
to play-fr...@googlegroups.com
Hi,

I have these models with no other references:

class Cart {
  @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL)
  @Column(nullable = true)
  public List<CartItem> cartItems;
}

class CartItem {
  @ManyToOne
  Cart cart;
}


Want to delete cartItems:

List<CartItem> items = cart.cartItems;
for(CartItem item: items) {
  item.delete();
}

throws Exception: Deleted entity passed to persist  ....



SOLUTIONS:

a) change cascade = CascadeType.ALL to cascade = CascadeType.REMOVE

OR

b) use this query:
List<CartItem> items = CartItem.find("cart=?", cart).fetch();

instead of this:
List<CartItem> items = cart.cartItems; 


I think that deletion via List<CartItem> items = cart.cartItems should work too ... is it fixable ?


Thank you
Daniel

Guillaume Bort

unread,
Jan 22, 2010, 5:06:50 AM1/22/10
to play-fr...@googlegroups.com
It depends ...

Do you save the cart object later ?

If so, it is the cause of your problem. Because the cart object still
contains a collection of deleted cartItems. And because the collection
is annotated with CascadeType.ALL, it will try to persist again the
deleted cartItem objects.

> --
> You received this message because you are subscribed to the Google Groups
> "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to
> play-framewor...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/play-framework?hl=en.
>

Daniel Guryca

unread,
Jan 22, 2010, 5:17:21 AM1/22/10
to play-fr...@googlegroups.com
No I do not save cart explicitly anywhere.

Daniel

Guillaume Bort

unread,
Jan 22, 2010, 5:20:26 AM1/22/10
to play-fr...@googlegroups.com
Ok I'll check that.

Guillaume Bort

unread,
Jan 22, 2010, 5:48:21 AM1/22/10
to play-fr...@googlegroups.com
So,

I cannot reproduce your problem. This simple action works as expected:

public static void delete(Long id) {
CartItem ci = CartItem.findById(id);
ci.delete();
index();
}

With this model:

@Entity
public class Cart extends Model {

@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL)

public List<CartItem> cartItems = new ArrayList();

}

and

@Entity
public class CartItem extends Model {

@ManyToOne
public Cart cart;

public CartItem(Cart cart) {
this.cart = cart;
cart.cartItems.add(this);
}

}

On Fri, Jan 22, 2010 at 11:20 AM, Guillaume Bort

Guillaume Bort

unread,
Jan 22, 2010, 5:51:49 AM1/22/10
to play-fr...@googlegroups.com
Well ok,

This one doesn't work:

public static void deleteAll(Long id) {
Cart cart = Cart.findById(id);


List<CartItem> items = cart.cartItems;
for(CartItem item: items) {
item.delete();
}

index();
}

...

On Fri, Jan 22, 2010 at 11:48 AM, Guillaume Bort

Guillaume Bort

unread,
Jan 22, 2010, 6:10:01 AM1/22/10
to play-fr...@googlegroups.com
Ok so,

As you know Hibernate (and JPA in general) automatically save all
persistent objects. Typically because cart has been loaded from the
database, JPA see it as a persistent instance and will try to save it
automatically. Now play uses a patch to discard this kind automatic
save on objects if you don't have called explicitly save() on them.

But in this case, hibernate do some kind of "in memory integrity
check" even before trying to save objects.

So you ends with a common hibernate problem:

The cartItems you have deleted are still referenced in the
cart.cartItems collection that is annotated for cascading persistence.
That's why hibernate throw this exception. If you delete a cartItem
object you need to explicitly remove it from the cartItems collection.

You can do this automatically by overriding the delete() method of the
CartItem class:

public class CartItem {

...

public CartItem delete() {
cart.cartItems.remove(this);
return super.delete();
}

}

Anyway my general advice is to avoid bi-directionnal relation
management with JPA. And if you really need it, be sure to manage
correctly both side of the relation (by adding, removing entities from
the other side collection).

On Fri, Jan 22, 2010 at 11:51 AM, Guillaume Bort

Daniel Guryca

unread,
Jan 22, 2010, 6:46:13 AM1/22/10
to play-fr...@googlegroups.com
Well, thanks for your explanation !

I usually avoid to use bi-directional mapings - so that's not a problem.

Cheers
Daniel
Reply all
Reply to author
Forward
0 new messages