繁体   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