我有一个包含多对一关系的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方法中的内容。