Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SpringDataJPA-如何持久化嵌套对象(无论是否存在)_Java_Spring Boot_Orm_Spring Data Jpa_Spring Data - Fatal编程技术网

Java SpringDataJPA-如何持久化嵌套对象(无论是否存在)

Java SpringDataJPA-如何持久化嵌套对象(无论是否存在),java,spring-boot,orm,spring-data-jpa,spring-data,Java,Spring Boot,Orm,Spring Data Jpa,Spring Data,使用Springboot 2.4.0,我试图开发一个简单的模块来管理实体产品和订单(多个关系)之间的典型关系 按顺序,我有以下产品字段: @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinTable( name="products_orders", joinColumns=@JoinColumn(name="order_id"),

使用Springboot 2.4.0,我试图开发一个简单的模块来管理实体
产品
订单
(多个关系)之间的典型关系

按顺序,我有以下
产品
字段:

@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;
我需要下一个订单,里面有很多产品。我有以下代码:

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

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

Order myorder = new Order(myListOfProducts, "mail", LocalDateTime.now());
myorder.save();
List myListOfProducts=new ArrayList();
添加(以前存在的产品);
添加(不存在的产品);
Order myorder=新订单(myListOfProducts,“mail”,LocalDateTime.now());
myorder.save();
问题是:是否可以使用以前的代码保存新订单以及与其链接的产品(保存现有和不存在的产品)

这是订单存储库:

public interface ProductRepository extends JpaRepository<Product, Integer>
public interface OrderRepository extends JpaRepository<Order, Integer>
公共接口OrderRepository扩展了JpaRepository 到目前为止,我得到的是:

  • 如果我将CascadeType更改为
    CascadeType.MERGE
    ,我只会将现有产品链接到新订单,但对于新产品,我会出现以下错误:
org.hibernate.transientObject异常:对象引用未保存的临时实例-在刷新之前保存临时实例:com.gallelloit.productcrud.model.Product;嵌套异常为java.lang.IllegalStateException:org.hibernate.TransientObject异常:对象引用未保存的临时实例-在刷新之前保存临时实例:com.gallelloit.productcrud.model.Product

  • 我对CascadeType(包括
    CascadeType.ALL
    )输入的任何其他值都会得到相反的结果:新产品会被保存并链接到新订单,但对于现有产品,我会得到以下错误:
已传递到持久化的分离实体: com.gallelloit.productcrud.model.Product;嵌套异常是 org.hibernate.PersistentObjectException:传递给的分离实体 persist:com.gallelloit.productcrud.model.Product

我知道我可以“手动”获取每个产品,并在下单之前保存它们。save(),但我想知道Spring Data是否为您做到了这一点


有什么想法吗?

依赖于
CascadeType.MERGE
在这种情况下是不安全的,因为它也会更新相关的
产品
s,这意味着您可能会无意中覆盖现有的
产品
数据

您可以通过要求JPA为现有实体创建代理来优化现有产品的获取,而不是从DB中实际获取它们的关联状态。这可以使用
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
对于
@manytomy
来说没有意义,因为它意味着
CascadeType.REMOVE
,这是您最不想要的


另外,我假设保存订单的逻辑发生在事务上下文中,对吗?

谢谢您的回答。该代码将放在哪里?我猜是在订单服务中,对吧?这是一个很好的解决办法。只有两个疑问。一个不太重要的问题是:它使我将productRepository注入OrderServiceImpl类中。这没什么大不了的。。。但到目前为止我还没有做过,现在我不得不这么做。正如我所说,没什么大不了的。另一个是:什么产品不存在,getOne方法返回null?我会在列表中插入空值吗?会有什么样的行为?我必须“手动”处理这种可能性吗?这个问题中的一个错误:“另一个是:任何产品不存在,getOne方法返回null?”它应该说:“另一个是:如果任何产品不存在,getOne方法返回null怎么办?”
getOne
从不返回
null
。JPA在使用
getOne
时不检查实体的存在性,这就是关键所在-以避免额外的查询。如果id没有指向
PRODUCT
表中的有效行,那么您将从DB获得完整性约束冲突,thoughPerfect。我最终在order.setProducts中执行了一些验证,方法与您所解释的类似。最后一个问题:JPA创建的代理是否响应代理设计模式?或者JPA创建了什么样的代理?你能为我参考一些文章来了解一下它们吗?谢谢!!最好的参考可能是。是的,它遵循代理模式,也就是说,如果你试图访问它的数据,它将被加载并返回,因此代理对于你的应用程序来说是透明的