While creating an online shop application using play-1.2.4
,I ran into some problems with jpa..I wanted to provide an admin area using the CRUD module
in play.Here ,an admin user can create/edit or delete the entities in the application(like Customer
s,Order
s,Item
s etc).
A Customer
can create Orders.Each Order
will have a Set of CartItem
s.When an Order
is deleted,the corresponding CartItem
s must be deleted.When a Customer
is deleted,all his Orders must be deleted as well.I thought I could get this by setting the cascade
property in jpa annotation.
I modelled it like this
Customer.java
@Entity
public class Customer extends Model {
@Email
@Required
public String email;
...
@OneToMany(mappedBy="customer", cascade=CascadeType.ALL)
public List<Order> orders;
@OneToOne
public PayMethod currentPayment;
...
}
Order.java
@Entity
public class Order extends Model {
@OneToMany( cascade=CascadeType.ALL,orphanRemoval=true,fetch=FetchType.EAGER)
public Set<CartItem> cartItems;
@ManyToOne
public Customer customer;
@ManyToOne
public PayMethod paymentMethod;
...
}
CartItem.java
@Entity
public class CartItem extends Model implements Comparable<CartItem>{
@ManyToOne
public Item item;
public int quantity;
}
PayMethod.java
@Entity
public class PayMethod extends Model {
@Required
public String cardNumber;
@ManyToOne
public Customer customer;
...
}
The following database tables were created
customer table
id | email | fullname | currentpayment_id
---|-------------|---------------|-----------------
2 |[email protected]| jon |29
order table
id |customer_id | paymentmethod_id
----+------------+-----------------
25 | 2 | 29
cartitem table
id | quantity | item_id
----+----------+---------
26 | 1 | 14
*order_cartitem table*
order_id | cartitems_id
----------+--------------
25 | 26
In the Admin interface created using CRUD(I haven't implented any methods ,just using the provided CRUD module as is),I tried to delete a Customer,but then,I get this error,
ERROR: update or delete on table "cartitem" violates foreign key constraint "fk7ff437ad3e28aa91" on table "order_cartitem"
Detail: Key (id)=(26) is still referenced from table "order_cartitem".
08:03:03,031 ERROR ~ Could not synchronize database state with session
Is there something wrong with the way I modelled the Entities? I thought the delete on the Customer
will be cascaded to Order
and that in turn will cascade to its CartItem
s .
What do I have to do to get this cascading effect?Or do I have to manually remove each contained instances of CartItem
s?
EDIT: As per Seb's reply
class Order extends Model {
@OneToMany(mappedBy="order", cascade=CascadeType.ALL,orphanRemoval=true,fetch=FetchType.EAGER)
public Set<CartItem> cartItems;
...
}
class CartItem extends Model implements Comparable<CartItem>{
@ManyToOne
public Item item;
public int quantity;
@ManyToOne
public Order order;
...
}
static void addItemToCart(Long itemId,Long orderId,String quantity) {
Item item = Item.findById(itemId);
Order order = Order.findById(orderId);
int qty = Integer.parseInt(quantity);
CartItem cartItem = new CartItem(item,qty);
cartItem.order=order;
order.addItem(cartItem, qty);
order.save();
...
}
This gets rid of order_cartitem table and adds a field order_id to cartitem table
cartitem table
id | quantity | item_id | order_id
----+----------+---------+----------
26 | 1 | 14 | 25
27 | 1 | 20 | 25
The admin(CRUD)
interface,lists the Customer
s and Order
s.When a particular Customer
(the one who created the Order
) is selected and the delete button is clicked,it results in a JPA error
JPA error
A JPA error occurred (Cannot commit): collection owner not associated with session: models.Order.cartItems
here is the stacktrace
If someone can understand why this is happening,please tell me.
Interestingly,I can click on the delete button
for a particular Order
,and it successfully calls the following controller method,
Admin.java
public static void deleteOrder(Long id) {
Order order = Order.findById(id);
order.delete();
...
}
which deletes the Order
and all its CartItem
s successfully..
So,why does this not happen when a Customer
is deleted?
Make your relation bidirectionnal by adding this to your cartitem class
@ManyToOne
public Order order;
and a mappedBy="order" in your cartItems @OneToMany
then hibernate will better handles your deletion. I am guessing that without this bidirectionnal link, hibernate tried to firstly set the column to null. You can also try to allow null values in your join table to see what happens if you don't want to enable the bidirectional relationship
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With