我有双向一对多关系。
0 or 1 client 0 个或多个列表产品订单.
应在两个实体上设置或取消设置该关系:
在客户端,我想设置分配给客户端的产品订单列表;然后应将客户端设置/取消设置为自动选择的订单。
在产品订单方面,我想设置分配订单的客户;然后,该产品订单应从其先前分配的客户列表中删除,并添加到新分配的客户列表中。
我想使用纯 JPA 2.0 注释和仅对实体管理器的一次“合并”调用(带有级联选项)。我尝试过以下代码片段,但它不起作用(我使用 EclipseLink 2.2.0 作为持久性提供程序)
@Entity
public class Client implements Serializable {
@OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
private List<ProductOrder> orders = new ArrayList<>();
public void setOrders(List<ProductOrder> orders) {
for (ProductOrder order : this.orders) {
order.unsetClient();
// don't use order.setClient(null);
// (ConcurrentModificationEx on array)
// TODO doesn't work!
}
for (ProductOrder order : orders) {
order.setClient(this);
}
this.orders = orders;
}
// other fields / getters / setters
}
@Entity
public class ProductOrder implements Serializable {
@ManyToOne(cascade= CascadeType.ALL)
private Client client;
public void setClient(Client client) {
// remove from previous client
if (this.client != null) {
this.client.getOrders().remove(this);
}
this.client = client;
// add to new client
if (client != null && !client.getOrders().contains(this)) {
client.getOrders().add(this);
}
}
public void unsetClient() {
client = null;
}
// other fields / getters / setters
}
持久化客户端的外观代码:
// call setters on entity by JSF frontend...
getEntityManager().merge(client)
持久化产品订单的门面代码:
// call setters on entity by JSF frontend...
getEntityManager().merge(productOrder)
在订单端更改客户分配时,效果很好:在客户端,订单将从之前的客户列表中删除,并添加到新客户的列表中(如果重新分配)。
BUT 在客户端更改时,我只能添加订单(在订单端,执行对新客户端的分配),但当我从客户端列表中删除订单时,它只是忽略(保存并刷新后,它们仍然在客户端的列表中,在订单端,他们也仍然分配给以前的客户。
只是为了澄清,我不想使用“删除孤儿”选项:从列表中删除订单时,不应将其从数据库中删除,但应更新其客户端分配(即更新为 null),如 Client#setOrders 方法中所定义。如何才能实现这一点?
EDIT: 感谢我在这里收到的帮助,我能够解决这个问题。请参阅下面我的解决方案:
客户端 (“一”/“拥有”方) 将已修改的订单存储在临时字段中。
@Entity
public class Client implements Serializable, EntityContainer {
@OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
private List<ProductOrder> orders = new ArrayList<>();
@Transient
private List<ProductOrder> modifiedOrders = new ArrayList<>();
public void setOrders(List<ProductOrder> orders) {
if (orders == null) {
orders = new ArrayList<>();
}
modifiedOrders = new ArrayList<>();
for (ProductOrder order : this.orders) {
order.unsetClient();
modifiedOrders.add(order);
// don't use order.setClient(null);
// (ConcurrentModificationEx on array)
}
for (ProductOrder order : orders) {
order.setClient(this);
modifiedOrders.add(order);
}
this.orders = orders;
}
@Override // defined by my EntityContainer interface
public List getContainedEntities() {
return modifiedOrders;
}
On the facade,在持久化时,它会检查是否还有任何必须持久化的实体。请注意,我使用了一个接口来封装此逻辑,因为我的外观实际上是通用的。
// call setters on entity by JSF frontend...
getEntityManager().merge(entity);
if (entity instanceof EntityContainer) {
EntityContainer entityContainer = (EntityContainer) entity;
for (Object childEntity : entityContainer.getContainedEntities()) {
getEntityManager().merge(childEntity);
}
}