簡體   English   中英

Spring-Data JPA:保存引用現有實體的新實體

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM