我有一个包含多对一关系的jpa持久化对象模型:一个Account有多个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对象。但是,当我创建一个事务,使用现有的已经持久化的帐户,并持久化的事务,我得到一个异常:

导致:org.hibernate.PersistentObjectException:传递给persist: com.paulsanwald.Account的分离实体 org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java: 141)

因此,我能够持久化一个包含事务的Account,但不能持久化一个具有Account的Transaction。我认为这是因为帐户可能没有附加,但这段代码仍然给了我相同的异常:

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

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


当前回答

这是我的药。

Below is my Entity. Mark that the id is annotated with @GeneratedValue(strategy = GenerationType.AUTO), which means that the id would be generated by the Hibernate. Don't set it when entity object is created. As that will be auto generated by the Hibernate. Mind you if the entity id field is not marked with @GeneratedValue then not assigning the id a value manually is also a crime, which will be greeted with IdentifierGenerationException: ids for this class must be manually assigned before calling save()

@Entity
@Data
@NamedQuery(name = "SimpleObject.findAll", query="Select s FROM SimpleObject s")
public class SimpleObject {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column
    private String key;

    @Column
    private String value;

}

这是我的主类。

public class SimpleObjectMain {

    public static void main(String[] args) {

        System.out.println("Hello Hello From SimpleObjectMain");

        SimpleObject simpleObject = new SimpleObject();
        simpleObject.setId(420L); // Not right, when id is a generated value then no need to set this.
        simpleObject.setKey("Friend");
        simpleObject.setValue("Bani");

        EntityManager entityManager = EntityManagerUtil.getEntityManager();
        entityManager.getTransaction().begin();
        entityManager.persist(simpleObject);
        entityManager.getTransaction().commit();

        List<SimpleObject> simpleObjectList = entityManager.createNamedQuery("SimpleObject.findAll").getResultList();
        for(SimpleObject simple : simpleObjectList){
            System.out.println(simple);
        }

        entityManager.close();
        
    }
}

我想救它的时候,它把它扔出去了

PersistentObjectException: detached entity passed to persist.

我所需要修复的是删除主方法中simpleObject的id设置行。

其他回答

如果没有任何帮助,并且您仍然得到这个异常,请检查equals()方法—并且不要在其中包含子集合。特别是当你有嵌入式集合的深层结构时(例如A包含B, B包含c,等等)。

以Account ->为例:

  public class Account {

    private Long id;
    private String accountName;
    private Set<Transaction> transactions;

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (!(obj instanceof Account))
        return false;
      Account other = (Account) obj;
      return Objects.equals(this.id, other.id)
          && Objects.equals(this.accountName, other.accountName)
          && Objects.equals(this.transactions, other.transactions); // <--- REMOVE THIS!
    }
  }

在上面的例子中,从equals()检查中删除事务。这是因为hibernate将暗示您不尝试更新旧对象,而是在更改子集合上的元素时传递一个新对象来持久化。 当然,这种解决方案并不适用于所有应用程序,您应该仔细设计想要包含在equals和hashCode方法中的内容。

所以我偶然发现了这个问题和答案,因为我得到了相同的错误,但一个非常基本的对象,只有字符串和整数。

但在我的情况下,我试图将一个值设置为一个带@Id注释的字段。

所以,如果你使用@Id,似乎你不能在一个类上创建一个新的对象,并自己设置一个Id,并将其持久化到数据库。然后,您应该将Id留空。我不知道,也许这对其他人有帮助。

解决方案很简单,只需使用CascadeType。MERGE而不是CascadeType。PERSIST或CascadeType.ALL。

我也遇到过同样的问题和CascadeType。MERGE对我很有效。

我希望你已经整理好了。

如果上述解决方案不工作,只需一次注释实体类的getter和setter方法,并且不设置id的值。(主键) 这样就可以了。

通过在下一个对象之前保存依赖对象来解决。

这发生在我身上,因为我没有设置Id(这不是自动生成的)。并试图拯救@ManytoOne的关系