[英]Spring Data JPA - How to persist nested object any existing or not
使用 Springboot 2.4.0,我正在嘗試開發一個簡單的模塊來管理實體Product
和Order
之間的典型關系(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.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.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.PERSIST
或CascadeType.ALL
,您當然可以將productRepository.save(product)
替換為product
。 但是, CascadeType.ALL
對@ManyToMany
沒有意義,因為它暗示了CascadeType.REMOVE
,這是您肯定不想要的。
另外,我假設保存訂單的邏輯發生在事務上下文中,對嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.