JPA/Hibernate:传递给持久化的分离实体

JPA/Hibernate:传递给持久化的分离实体

我有一个JPA持久化的对象模型,它包含一个多对一的关系:一个帐户有许多事务。交易只有一个帐户。

下面是代码片段:

@Entitypublic class Transaction {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
    private Account fromAccount;....@Entitypublic class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")
    private Set<Transaction> transactions;

我能够创建一个帐户对象,向它添加事务,并正确地持久化帐户对象。但是,当我创建一个交易时,使用现有的已持久化帐户,并坚持交易我有个例外:

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.paulsanwald.Account
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)

因此,我能够持久化一个包含事务的帐户,而不是一个有帐户的事务。我认为这是因为帐户可能没有附加,但这段代码仍然给了我同样的例外:

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);

如何正确保存与已持久化帐户对象关联的事务?


潇湘沐
浏览 570回答 3
3回答

红糖糍粑

这是一个典型的双向一致性问题。您需要在双向关系的两边修复设置者。更正设置器后,要将实体访问类型声明为“Property”。声明“Property”访问类型的最佳实践是将所有注释从成员属性移动到相应的getter。一个重要的警告是不要将“Field”和“Property”访问类型混合在实体类中,否则JSR-317规范就没有定义这种行为。

不负相思意

解决方案很简单,只需使用CascadeType.MERGE而不是CascadeType.PERSIST或CascadeType.ALL.我也有过同样的问题CascadeType.MERGE为我工作过。我希望你能解决。

jeck猫

使用合并是危险和棘手的,因此在您的情况下,这是一个肮脏的解决方法。您至少需要记住,当您传递要合并的实体对象时,它停下来被附加到事务中,而是返回一个新的、现在附加的实体。这意味着,如果任何人仍然拥有旧的实体对象,则对其的更改将被静默忽略,并在提交时丢弃。您没有在这里显示完整的代码,所以我不能再次检查您的事务模式。要达到这样的情况,一种方法是在执行合并和持久化时没有活动的事务。在这种情况下,持久性提供程序将为您执行的每个JPA操作打开一个新事务,并在调用返回之前立即提交并关闭它。如果是这样的话,合并将在第一个事务中运行,然后在Merge方法返回之后,事务被完成并关闭,返回的实体现在被分离。下面的持久化将打开第二个事务,并试图引用一个被分离的实体,从而提供一个异常。始终将代码包装在事务中,除非您非常清楚自己在做什么。使用容器管理的事务,它看起来像这样。注意:这假设方法在会话bean中,并通过本地或远程接口调用。@TransactionAttribute(TransactionAttributeType.REQUIRED)public&nbsp;void&nbsp;storeAccount(Account&nbsp;account)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(account.getId()!=null)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;account&nbsp;=&nbsp;entityManager.merge(account); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;Transaction&nbsp;transaction&nbsp;=&nbsp;new&nbsp;Transaction(account,"other&nbsp;stuff"); &nbsp;&nbsp;&nbsp;&nbsp;entityManager.persist(account);}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java