【发布时间】:2012-06-17 06:13:54
【问题描述】:
我与以下实体类具有双向一对多关系:
0 或 1 个客户 0 或更多产品订单
在持久化客户端实体时,我希望关联的产品订单实体也可以持久化(因为它们对“父”客户端的外键可能已更新)。
当然,所有必需的 CASCADE 选项都是在客户端设置的。但是如果新创建的客户端在引用现有产品订单时第一次被持久化,则它不起作用,如在这种情况下:
- 产品订单“1”已创建并保留。工作正常。
- 客户端“2”已创建,产品订单“1”已添加到其产品订单列表中。然后它被持久化。不起作用。
我尝试了几种方法,但都没有显示出预期的结果。请参阅下面的结果。我在这里阅读了所有相关问题,但它们对我没有帮助。我在 GlassFish 3.1.2 上的 Apache Derby (JavaDB) 内存数据库中使用 EclipseLink 2.3.0、纯 JPA 2.0 注释和 JTA 作为事务类型。实体关系由 JSF GUI 管理。对象级关系管理有效(除了持久化),我用 JUnit 测试对其进行了测试。
方法 1)“默认”(基于 NetBeans 类模板)
客户:
@Entity
public class Client implements Serializable, ParentEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "client", cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH},
fetch= FetchType.LAZY)
private List<ProductOrder> orders = new ArrayList<>();
// other fields, getters and setters
}
产品订单:
@Entity
public class ProductOrder implements Serializable, ChildEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne // owning side
private Client client;
// other fields, getters and setters
}
通用持久性外观:
// Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
getEntityManager().persist(entity);
}
// Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
getEntityManager().merge(entity);
}
结果:
create() 立即抛出此异常:
警告:调用 EJB 期间发生系统异常 ClientFacade 方法 public void javaee6test.beans.AbstractFacade.create(java.lang.Object) javax.ejb.EJBException:事务中止...
原因: javax.transaction.RollbackException:标记为回滚的事务。 ...
原因:异常 [EclipseLink-4002](Eclipse 持久性 服务 - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException 内部 异常:java.sql.SQLIntegrityConstraintViolationException: 语句被中止,因为它会导致重复键 标识的唯一或主键约束或唯一索引中的值 由在“PRODUCTORDER”上定义的“SQL120513133540930”。错误代码:-1 调用:INSERT INTO PRODUCTORDER (ID, CLIENT_ID) VALUES (?, ?) bind => 【2个参数绑定】查询: InsertObjectQuery(javaee6test.model.ProductOrder[ id=1 ]) ...
原因: java.sql.SQLIntegrityConstraintViolationException:该语句是 中止,因为它会导致唯一的键值重复 或主键约束或唯一索引 在“PRO-DUCTORDER”上定义的“SQL120513133540930”。 ...
原因: org.apache.derby.client.am.SqlException:语句被中止 因为它会导致唯一或 主键约束或唯一索引由 在“PRODUCTOR-DER”上定义的“SQL120513133540930”。
我不明白这个例外。编辑()工作正常。但是我想在创建时向客户添加产品订单,所以这还不够。
方法 2)仅合并()
对通用持久性外观的更改:
// Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
getEntityManager().merge(entity);
}
// Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
getEntityManager().merge(entity);
}
结果:
在 create() 时,EclipseLink 日志输出显示:
很好:插入客户(ID、NAME、ADDRESS_ID)值(?、?、?) bind => [绑定3个参数]
但产品订单表上没有“更新”。因此,关系不成立。另一方面,edit() 同样可以正常工作。
方法 3) 两种实体类型的 Id GenerationType.IDENTITY
对客户和产品订单类的更改:
...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
结果:
在 create() 时,EclipseLink 日志输出显示:
很好:INSERT INTO CLIENT (NAME, ADDRESS_ID) VALUES (?, ?) bind => [2 参数绑定]
很好:值 IDENTITY_VAL_LOCAL()
很好:插入 PRODUCTORDER (ORDERDATE, CLIENT_ID) VALUES (?, ?) bind => [2 参数绑定]
很好:值 IDENTITY_VAL_LOCAL()
因此,不是建立与添加到客户列表中的产品订单的关系,而是创建并保留一个新的产品订单实体(!),并建立与该实体的关系。同样在这里,edit() 工作正常。
方法 4) 方法 (2) 和 (3) 结合
结果:与方法(2)相同。
我的问题是:有没有办法实现上述场景?如何归档?我想继续使用 JPA(没有特定于供应商的解决方案)。
【问题讨论】:
标签: java jpa jpa-2.0 entity-relationship jta