我有一个JPA持久对象模型,其中包含多对一关系:一个Account具有许多Transactions。A Transaction有一个Account。
Account
Transactions
Transaction
这是一段代码:
@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,位于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对象关联的?
这是一个典型的双向一致性问题。在此链接以及此链接中都进行了很好的讨论。
根据前面2个链接中的文章,您需要在双向关系的两侧修复设置器。此链接中有一个用于一侧的设置器示例。
此链接中提供了很多方面的示例设置器。
在更正了设置者之后,您想要将实体访问类型声明为“属性”。声明“属性”访问类型的最佳实践是将所有注释从成员属性移至相应的getter。一个大的警告是不要在实体类中混合使用“字段”和“属性”访问类型,否则JSR-317规范未定义其行为。