我有一个包含多对一关系的 JPA 持久对象模型:一个 Account
有很多 Transactions
。一个 Transaction
有一个 Account
。
这是代码片段:
@Entity
public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
private Account fromAccount;
....
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")
private Set<Transaction> transactions;
我能够创建一个 Account
对象,向其添加事务,并正确保留 Account
对象。但是,当我创建交易时, 使用现有的已经持久化的 Account 并持久 化 Transaction ,我得到一个异常:
由以下原因引起:org.hibernate.PersistentObjectException:传递给持久化的分离实体:com.paulsanwald.Account at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
因此,我能够保留包含事务的 Account
,但不保留包含 Account
的事务。我认为这是因为 Account
可能没有附加,但这段代码仍然给我同样的例外:
if (account.getId()!=null) {
account = entityManager.merge(account);
}
Transaction transaction = new Transaction(account,"other stuff");
// the below fails with a "detached entity" message. why?
entityManager.persist(transaction);
如何正确保存 Transaction
,与已经存在的 Account
对象相关联?
原文由 Paul Sanwald 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是一个典型的双向一致性问题。在 此链接 和 此链接中对此进行了很好的讨论。
根据前两个链接中的文章,您需要修复双向关系两侧的设置器。一侧的示例设置器位于 此链接中。
许多方面的示例设置器位于 此链接中。
更正设置器后,您希望将实体访问类型声明为“属性”。声明“属性”访问类型的最佳做法是将所有注释从成员属性移动到相应的获取器。一个重要的警告是不要在实体类中混合“字段”和“属性”访问类型,否则 JSR-317 规范未定义该行为。