简体   繁体   English

Spring 数据 JPA - 如何保留任何现有的嵌套 object

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

Using Springboot 2.4.0, I am trying to develop a simple module to manage a tipical relationship between the entities Product and Order (ManyToMany relationship).使用 Springboot 2.4.0,我正在尝试开发一个简单的模块来管理实体ProductOrder之间的典型关系(ManyToMany 关系)。

In Order, I have this products field:为了,我有这个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;

Since I don't need it, for now I am omitting an orders field in the Product entity.因为我不需要它,所以现在我在Product实体中省略了一个orders字段。

Previous to this relationship, I have a CRUD for Product entity up and properly running, so I can insert products through a Product Repository:在此关系之前,我有一个Product实体的 CRUD 并正常运行,因此我可以通过产品存储库插入产品:

public interface ProductRepository extends JpaRepository<Product, Integer>

I need to place an order with a number of products within it.我需要下订单,里面有很多产品。 I have this code:我有这个代码:

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

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

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

The question is: is it possible to get with the previous code that the new order gets saved as well as the products linked to it (saving both the existing and non existing products)?问题是:是否有可能使用先前的代码来保存新订单以及与之关联的产品(同时保存现有和非现有产品)?

This is the Order Repository:这是订单库:

public interface OrderRepository extends JpaRepository<Order, Integer>

This is what I got so far:这是我到目前为止得到的:

  • If I change CascadeType to CascadeType.MERGE , I get to link only existing products to the new order, but for new Products, I get this error:如果我将 CascadeType 更改为CascadeType.MERGE ,我只能将现有产品链接到新订单,但对于新产品,我会收到以下错误:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.gallelloit.productcrud.model.Product; 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 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

  • Any other value I put to CascadeType (including CascadeType.ALL ), I get the opposite: new products are saved and linked to the new order, but for existing products, I get this error:我为 CascadeType 设置的任何其他值(包括CascadeType.ALL ),我得到相反的结果:新产品被保存并链接到新订单,但对于现有产品,我收到此错误:

detached entity passed to persist: com.gallelloit.productcrud.model.Product;分离实体传递给持久化:com.gallelloit.productcrud.model.Product; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.gallelloit.productcrud.model.Product嵌套异常是 org.hibernate.PersistentObjectException:分离的实体传递给持久化:com.gallelloit.productcrud.model.Product

I know that I can do it "manually" getting each of the products, and saving them before the order.save() , but I was wondering if Spring Data did it for you.我知道我可以“手动”获取每个产品,并在order.save()之前保存它们,但我想知道 Spring Data 是否为你做到了。

Any idea?任何想法?

Relying on CascadeType.MERGE is not safe in this context, because it updates the associated Product s as well, meaning you may unintentionally overwrite existing Product data.在这种情况下,依赖CascadeType.MERGE是不安全的,因为它也会更新关联的Product ,这意味着您可能会无意中覆盖现有的Product数据。

You can optimize the fetching of existing products by asking JPA to create proxies for the existing entities instead of actually fetching their associated state from the DB.您可以通过要求 JPA 为现有实体创建代理而不是实际从数据库中获取其关联的 state 来优化现有产品的获取。 This can be done using JpaRepository.getOne() .这可以使用JpaRepository.getOne()来完成。 You'll need sth like:你需要这样的东西:

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

If you decide on using CascadeType.PERSIST or CascadeType.ALL , you can of course replace productRepository.save(product) with just product .如果您决定使用CascadeType.PERSISTCascadeType.ALL ,您当然可以将productRepository.save(product)替换为product CascadeType.ALL doesn't make sense for @ManyToMany , though, since it implies CascadeType.REMOVE , which you most certainly don't want.但是, CascadeType.ALL@ManyToMany没有意义,因为它暗示了CascadeType.REMOVE ,这是您肯定不想要的。

Also, I'm assuming the logic of saving the order happens inside a transactional context, right?另外,我假设保存订单的逻辑发生在事务上下文中,对吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM