Java JPA和JTA:持久化实体和合并级联子实体
我与以下实体类有双向一对多关系: 0或1个客户0或更多产品订单 在持久化客户机实体时,我希望关联的产品订单实体也被持久化(因为它们对“父”客户机的外键可能已经更新) 当然,所有必需的级联选项都是在客户端设置的。但是如果在引用现有产品订单时第一次持久化新创建的客户机,则它不起作用,如本场景中所示:Java JPA和JTA:持久化实体和合并级联子实体,java,jpa,jpa-2.0,entity-relationship,jta,Java,Jpa,Jpa 2.0,Entity Relationship,Jta,我与以下实体类有双向一对多关系: 0或1个客户0或更多产品订单 在持久化客户机实体时,我希望关联的产品订单实体也被持久化(因为它们对“父”客户机的外键可能已经更新) 当然,所有必需的级联选项都是在客户端设置的。但是如果在引用现有产品订单时第一次持久化新创建的客户机,则它不起作用,如本场景中所示: 已创建并保留产品订单“1”。很好 已创建客户端“2”,并将产品订单“1”添加到其产品订单列表中。然后它被持久化。不起作用 我尝试了几种方法,但都没有达到预期的效果。请参见下面的结果。我在这里阅读了所有相
@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
}
通用持久性外观:
// 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);
}
// 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()立即抛出此异常:
警告:在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
调用:插入PRODUCTORDER(ID,客户端ID)值(?,)bind=>
[2参数绑定]查询:
InsertObjectQuery(javaee6test.model.ProductOrder[id=1])
原因:
java.sql.SQLIntegrityConstraintViolationException:语句为
已中止,因为这会在唯一的
或主键约束或由标识的唯一索引
“PRO-DUCTORDER”上定义的“SQL120513133540930”
原因:
org.apache.derby.client.am.SqlException:语句被中止
可能是因为它会导致在唯一或
主键约束或由标识的唯一索引
在“PRODUCTOR-DER”上定义了“SQL120513133540930”
我不理解这个例外。edit()工作正常。但我想在客户机创建时向其添加产品订单,因此这是不够的
方法2)仅合并()
对通用持久性外观的更改:
// 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);
}
// 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、名称、地址\u ID)中插入值(?、、?)
绑定=>[3个参数绑定]
但产品订单表上没有“更新”。因此,这种关系尚未建立。另一方面,edit()也可以正常工作
Apporach 3)两种实体类型上的Id GenerationType.IDENTITY
对客户和产品订单类别的更改:
...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
结果:
在create()上,EclipseLink日志记录输出显示:
精细:将值(?,)bind=>[2]插入到客户机(名称、地址\u ID)中
参数绑定]
Fine:values IDENTITY\u VAL\u LOCAL()
好的:插入到
PRODUCTORDER(ORDERDATE,客户端ID)值(?,)绑定=>[2
参数绑定]
Fine:values IDENTITY\u VAL\u LOCAL()
因此,不再建立与添加到客户列表中的产品订单的关系,而是创建并保留一个新的prodcut订单实体(!),并建立与该实体的关系。这里也一样,edit()可以正常工作
近似4)方法(2)和(3)组合
结果:与方法(2)相同
我的问题是:有没有办法实现上述场景?如何归档?我想继续使用JPA(无供应商特定解决方案)。在ProductOrder实体中使用@Joincolumn注释,请参见下文
@Entity
public class ProductOrder implements Serializable, ChildEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne // owning side
@JoinColumn(name = "PRODUCTORDER_ID", referencedColumnName = "ID")
//write your database column names into name and referencedColumnName attributes.
private Client client;
// other fields, getters and setters
}
确保您正在设置关系的双方,您不能只将订单添加到客户机,还需要设置订单的客户机。此外,还需要合并已更改的两个对象。如果您只是合并客户机,那么订单的客户机将不会被合并(尽管您的级联导致它被合并) 持久化不起作用,因为持久化要求被持久化的对象对于持久化上下文是正确的,即不引用分离的对象,它必须引用托管对象
您的问题来自于您分离对象。如果不拆离对象,则不会出现相同的问题。通常在JPA中,您将创建一个EntityManager,查找/查询您的对象,编辑/持久化它们,调用commit。不需要合并。您好,我今天遇到了同样的问题,我向openJPA邮件列表发送此电子邮件: 嗨。我在同一实体中插入和更新引用时遇到问题 我试图插入一个新的对象(考试),它引用了另一个对象(人),同时我想更新这个人对象的属性(生日)。虽然我将CascadeType设置为ALL,但更新从未发生。唯一可行的方法是执行持久化,然后执行合并操作。这正常吗?我需要改变什么吗 我不喜欢这个主意
// Called when pressing "save" on the "edit..."
public void edit(T entity) {
getEntityManager().merge(entity);}
client.set..(some property to be saved);
productOrder.set..(some property to be saved);
List<ProductOrder> order = new ArrayList<>();
productOrder.setClient(productOrder);
.edit(client) or .edit(productOrder)