【发布时间】:2012-05-17 11:20:55
【问题描述】:
我有一个双向的一对多关系。
0 或 1 个客户 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)
在订单端更改客户分配时,效果很好:在客户端,订单从先前客户的列表中删除,并添加到新客户的列表中(如果重新分配)。
但是在客户端更改时,我只能添加订单(在订单端,执行分配给新客户端),但是当我从客户端列表中删除订单时它会忽略(保存刷新后,在客户端仍然在列表中,在订单端,也仍然分配给之前的客户端。
澄清一下,我不想使用“删除孤儿”选项:从列表中删除订单时,不应将其从数据库中删除,但其客户分配应该是根据 Client#setOrders 方法中的定义更新(即为 null)。如何归档?
编辑:感谢我在这里得到的帮助,我能够解决这个问题。请参阅下面的解决方案:
客户端(“One”/“owned”方)将已修改的订单存储在临时字段中。
@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;
}
在外观上,持久化时,它也会检查是否有任何实体必须持久化。请注意,我使用了一个接口来封装这个逻辑,因为我的外观实际上是通用的。
// 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);
}
}
【问题讨论】:
标签: java jpa jpa-2.0 entity-relationship one-to-many