簡體   English   中英

Spring 數據 JPA - 如何保留任何現有的嵌套 object

[英]Spring Data JPA - How to persist nested object any existing or not

使用 Springboot 2.4.0,我正在嘗試開發一個簡單的模塊來管理實體ProductOrder之間的典型關系(ManyToMany 關系)。

為了,我有這個products領域:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
        name="products_orders",
        joinColumns=@JoinColumn(name="order_id"),
        inverseJoinColumns=@JoinColumn(name="product_id")
)
private List<Product> products;

因為我不需要它,所以現在我在Product實體中省略了一個orders字段。

在此關系之前,我有一個Product實體的 CRUD 並正常運行,因此我可以通過產品存儲庫插入產品:

public interface ProductRepository extends JpaRepository<Product, Integer>

我需要下訂單,里面有很多產品。 我有這個代碼:

List<Products> myListOfProducts = new ArrayList<>();

myListOfProducts.add(previouslyExistingProduct);
myListOfProducts.add(nonExistingProduct);

Order myorder = new Order(myListOfProducts, "mail", LocalDateTime.now());
myorder.save();

問題是:是否有可能使用先前的代碼來保存新訂單以及與之關聯的產品(同時保存現有和非現有產品)?

這是訂單庫:

public interface OrderRepository extends JpaRepository<Order, Integer>

這是我到目前為止得到的:

  • 如果我將 CascadeType 更改為CascadeType.MERGE ,我只能將現有產品鏈接到新訂單,但對於新產品,我會收到以下錯誤:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.gallelloit.productcrud.model.Product; nested exception is java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.gallelloit.productcrud.model.Product

  • 我為 CascadeType 設置的任何其他值(包括CascadeType.ALL ),我得到相反的結果:新產品被保存並鏈接到新訂單,但對於現有產品,我收到此錯誤:

分離實體傳遞給持久化:com.gallelloit.productcrud.model.Product; 嵌套異常是 org.hibernate.PersistentObjectException:分離的實體傳遞給持久化:com.gallelloit.productcrud.model.Product

我知道我可以“手動”獲取每個產品,並在order.save()之前保存它們,但我想知道 Spring Data 是否為你做到了。

任何想法?

在這種情況下,依賴CascadeType.MERGE是不安全的,因為它也會更新關聯的Product ,這意味着您可能會無意中覆蓋現有的Product數據。

您可以通過要求 JPA 為現有實體創建代理而不是實際從數據庫中獲取其關聯的 state 來優化現有產品的獲取。 這可以使用JpaRepository.getOne()來完成。 你需要這樣的東西:

order.setProducts(order.getProducts()
    .map(product -> product.getId() == null ? productRepository.save(product) : productRepository.getOne(product.getId())
    .collect(Collectors.toList());

如果您決定使用CascadeType.PERSISTCascadeType.ALL ,您當然可以將productRepository.save(product)替換為product 但是, CascadeType.ALL@ManyToMany沒有意義,因為它暗示了CascadeType.REMOVE ,這是您肯定不想要的。

另外,我假設保存訂單的邏輯發生在事務上下文中,對嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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