[英]Spring-Data JPA: save new entity referencing existing one
問題基本上與下面的問題相同:
JPA級聯持久化並且對分離實體的引用會拋出PersistentObjectException。 為什么?
我正在創建一個引用現有的獨立實體的新實體。 現在,當我在Spring數據存儲庫中保存此實體時,會拋出異常:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist
如果我們看一下spring數據JPA的源代碼中的save()方法,我們看到:
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
如果我們在AbstractEntityInformation
查看isNew()
public boolean isNew(T entity) {
return getId(entity) == null;
}
所以基本上如果我保存()一個新實體(id == null)
,spring數據將始終調用persist,因此這種情況總是會失敗。
在向集合添加新項目時,這似乎是一個非常典型的用例。
我該如何解決這個問題?
編輯1:
注意:
此問題與如何保存引用Spring JPA中現有實體的新實體沒有直接關系? 。 詳細說明假設您獲得了通過http創建新實體的請求。 然后,您從請求中提取信息,並創建您的實體和現有的實體。 因此,他們將永遠脫離。
我有一個類似的問題,我試圖用一個已保存的實體對象保存一個新的實體對象。
我所做的是實現了Persistable <T>並相應地實現了isNew()。
public class MyEntity implements Persistable<Long> {
public boolean isNew() {
return null == getId() &&
subEntity.getId() == null;
}
或者您可以使用AbstractPersistable並覆蓋那里的isNew。
我不知道這是否會被認為是處理這個問題的好方法,但它對我來說非常好,而且感覺非常自然。
我想出的最好的是
public final T save(T containable) {
// if entity containable.getCompound already exists, it
// must first be reattached to the entity manager or else
// an exception will occur (issue in Spring Data JPA ->
// save() method internal calls persists instead of merge)
if (containable.getId() == null
&& containable.getCompound().getId() != null){
Compound compound = getCompoundService()
.getById(containable.getCompound().getId());
containable.setCompound(compound);
}
containable = getRepository().save(containable);
return containable;
}
我們檢查我們是否處於有問題的情況,如果是,只需通過其id從數據庫重新加載現有實體,並將新實體的字段設置為這個新加載的實例。 然后它將被附加。
這要求新實體的服務保存對引用實體的服務的引用。 這應該不是問題,因為無論如何都要使用spring,以便可以將服務添加為新的@Autowired
字段。
然而,另一個問題(在我的情況下,這種行為實際上是期望的)你不能在保存新實體的同時更改引用的現有實體。 所有這些變化都將被忽略。
重要的提示:
在許多情況下,可能是您的情況,這可能會簡單得多。 您可以向服務添加實體管理器的引用:
@PersistenceContext
private EntityManager entityManager;
以及if(){}
塊使用
containable = entityManager.merge(containable);
而不是我的代碼(如果它工作未經測試)。
在我的例子中,類是抽象的,而@ManyToOne
targetEntity
也是抽象的。 直接調用entityManager.merge(可包含)然后會導致異常。 但是,如果你的課程都是具體的,這應該有效。
我將@EmbeddedId
和業務數據作為id的一部分存在同樣的問題。
知道實體是否是新的唯一方法是執行(em.find(entity)==null)?em.persist(entity):em.merge(entity)
但是spring-data只提供了save()
方法,並且沒有辦法用find()
方法填充Persistable.isNew()
find()
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.