[英]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,我正在尝试开发一个简单的模块来管理实体
Product
和Order
之间的典型关系(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:这是我到目前为止得到的:
CascadeType.MERGE
, I get to link only existing products to the new order, but for new Products, I get this error: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
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.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.PERSIST
或CascadeType.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.