使用play-1.2.4
创建在线商店应用程序时,我遇到了jpa的一些问题。我想在play中使用CRUD module
提供管理区域。这里,管理员用户可以创建/编辑或删除应用程序中的实体(如Customer
s,Order
s,Item
等)。
Customer
可以创建订单。每个Order
都会有一组CartItem
s。当Order
被删除时,相应的CartItem
必须当删除Customer
时,他的所有订单也必须删除。我想我可以通过在jpa注释中设置cascade
属性来实现这一点。
我像这样建模了
的 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;
...
}
创建了以下数据库表
客户表
id | email | fullname | currentpayment_id
---|-------------|---------------|-----------------
2 |jon@gmail.com| jon |29
订购表
id |customer_id | paymentmethod_id
----+------------+-----------------
25 | 2 | 29
购物台表
id | quantity | item_id
----+----------+---------
26 | 1 | 14
* order_cartitem表*
order_id | cartitems_id
----------+--------------
25 | 26
在使用CRUD创建的Admin界面中(我没有实现任何方法,只是按原样使用提供的CRUD模块),我试图删除一个Customer,但是,我得到了这个错误,
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
我对实体进行建模的方式有问题吗?我认为Customer
上的删除会级联到Order
,然后会级联到CartItem
。
我需要做些什么来获得这种级联效果?或者我是否必须手动删除每个包含CartItem
s的实例?
编辑:根据Seb的回复
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();
...
}
这摆脱了 order_cartitem 表,并将字段 order_id 添加到 cartitem表
购物台表
id | quantity | item_id | order_id
----+----------+---------+----------
26 | 1 | 14 | 25
27 | 1 | 20 | 25
admin(CRUD)
界面,列出了Customer
和Order
s。当选择了Customer
(创建Order
的人)时,单击删除按钮,结果为JPA error
JPA error
A JPA error occurred (Cannot commit): collection owner not associated with session: models.Order.cartItems
如果有人能理解为什么会这样,请告诉我。
有趣的是,我可以点击特定delete button
的{{1}},并成功调用以下控制器方法,
的 Admin.java 的
Order
成功删除public static void deleteOrder(Long id) {
Order order = Order.findById(id);
order.delete();
...
}
及其所有Order
个..
那么,为什么在删除CartItem
时不会发生这种情况?
答案 0 :(得分:2)
通过将此关系添加到您的cartitem类
,使您的关系双向化@ManyToOne
public Order order;
和mappedBy =&#34; order&#34;在你的cartItems @OneToMany
然后hibernate会更好地处理你的删除。我猜测,没有这个双向链接,hibernate试图首先将列设置为null。您还可以尝试在联接表中允许空值,以查看如果您不想启用双向关系会发生什么
答案 1 :(得分:0)
JPA的级联属性存在问题。尝试使用来自hibernate的相关级联注释,并删除从JPA中使用的所有级联。以下是PayMethod模型类的示例:
// Be careful, import the realted annotations from hibernate (not JPA)
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class PayMethod extends Model {
@Required
public String cardNumber;
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
public Customer customer;
...
}
上面的方法适用于我的单向映射。我希望这能解决你的问题。
答案 2 :(得分:0)
我有类似的问题,但我没有使用List,我使用的是实体数组。
我的包装实体的问题是它没有像我通常对我的列表那样初始化数组(new MyEntity [0])(新的ArrayList(0))。
我意识到(经验方法)当尝试将“merge”调用到由“all-delete-orphan”关系关联的“null”数组时,“org.hibernate.AssertionFailure:集合所有者与会话无关: “起来了。
所以我的建议是:当使用“all-delete-orphans”关系时,用空实例初始化你的集合(包括数组)。