spring-boot - OneToMany双向关系JoinColumn值在Spring Data JPA中为null
问题描述
我有两个实体 Cart 和 CartProduct 的 OneToMany 双向映射。每当我们插入带有购物车产品的 Cart 对象时,CartProduct 表应该填充cart_id
. 这是问题,当我插入购物车对象时,一切似乎都很好,除了JoinColumn(card_id)
导致 CartProduct 表中的空值。我这样做对吗?
购物车.Java
package com.springtesting.model.cart;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.springtesting.model.AbstractAuditingEntity;
import com.springtesting.model.user.UserProfile;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Entity
@Data
@Table(name = "cart")
public class Cart extends AbstractAuditingEntity
{
private static final long serialVersionUID = 6294902210705780249L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@OneToOne
@JoinColumn(name = "user_profile_id")
@JsonIgnoreProperties(value = {"addresses"})
private UserProfile userProfile;
@ManyToOne
@JoinColumn(name = "cart_status")
private CartStatus cartStatus;
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL,fetch = FetchType.EAGER)
//@ElementCollection(targetClass = CartProduct.class)
private List<CartProduct> cartProducts=new ArrayList<>();
}
购物车产品.Java
package com.springtesting.model.cart;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.springtesting.model.AbstractAuditingEntity;
import com.springtesting.model.product.Product;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
@EqualsAndHashCode(callSuper = true)
@Entity
@Data
@Table(name = "cart_product")
public class CartProduct extends AbstractAuditingEntity
{
private static final long serialVersionUID = 6498067041321289048L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@OneToOne
@JoinColumn(name = "product_id")
private Product product;
@Column(name = "quantity")
private Integer quantity;
@ManyToOne
@JoinColumn(name = "cart_id",referencedColumnName = "id")
@JsonIgnoreProperties(value = {"userProfile","cartStatus","cartProducts"})
private Cart cart;
}
测试用例.java
@Test
public void insertCart()
{
Cart cart=new Cart();
cart.setUserProfile(userProfileRepository.findAllByUserId(1L).get());
cart.setCartStatus(cartStatusRepository.findById(1L).get());
List<CartProduct> cartProducts=new ArrayList<>();
CartProduct cartProduct=new CartProduct();
cartProduct.setProduct(productRepository.findById(1L).get());
cartProduct.setQuantity(2);
cartProducts.add(cartProduct);
cartProduct=new CartProduct();
cartProduct.setProduct(productRepository.findById(2L).get());
cartProduct.setQuantity(1);
cartProducts.add(cartProduct);
cart.setCartProducts(cartProducts);
cartRepository.saveAndFlush(cart);
}
解决方案
是的,您的解决方法是添加cartProduct.setCart(cart);
这是因为 CartProduct 是拥有实体并且是 foreignKey 的保管人。上面的语句设置了 FK。
思考这个问题的方法是 的概念owning entity
。当你有mappedBy="cart"
你说CartProduct
班级拥有关系。这意味着只有CartProduct
类在做持久化。这告诉 JPA 在CartProduct
表中创建一个 FK。但是,我们注意到 save 没有被调用,CartProduct
而是被调用,Cart
但cartProducts
仍然被保存。这是因为您有cascade = CascadeType.ALL
注释。这告诉 JPA 在完成某些操作时将其级联到Cart
,在本例中为save
操作。
您应该打印 SQL 语句并检查不同配置和测试用例的差异。这将帮助您更好地理解。
您还有 FetchType.EAGER。这通常是一个坏习惯,通常会导致无穷无尽的问题。
考虑双向映射的一个好方法是它List<CartProducts> cartProducts
是一个仅限查询的字段。为了保存CartProduct
你可以直接调用 save cartProductRepository
。例如
CartProduct cartProduct=new CartProduct();
cartProduct.setProduct(productRepository.findById(1L).get());
cartProduct.setQuantity(2);
cartProduct.setCart(cart);
cartProductRepository.save(cartProduct);
接着
cart.getCartProducts().add(cartProduct);
并删除所有级联和急切的 fetch 注释。当hibernate说你必须管理关系的双方时,这就是这个意思。
这样做会导致一个保存查询。通过使用级联注释,您会发现当您将项目添加到购物车并对其调用 save 时,生成的 sql 将首先cartProducts
从数据库中删除所有现有项目,并在每次调用 save 时将它们与新项目一起重新添加。对于有 10 件物品而不是单个保存的购物车,您将有一个删除和 10 个新保存。肯定不太理想。如果您必须从头开始重新加载购物车,最有效的方法是获取购物车,然后cart.setCartProducts(cartProductRepository.findAllByCart(cart));
这就是 FetchType.EAGER 正在做的事情。= new ArrayList<>();
当你明白这一切时,你就会意识到你不需要一个cartProducts.
推荐阅读
- c - x86 上的 Bison/Lex 段错误,但在 arm 上运行
- typescript - TypeScript 没有捕获未定义的变量?
- jquery - 如何为多个元素设置脚本
- angularjs - Angular Promise 有条件的
- python - 处理 api 中的 url 部分返回的 json 格式
- julia - Julia 1.0.0:`=>` 运算符有什么作用?
- javascript - 在手机上滚动失败
- jquery - 语义 UI 模式一打开就关闭
- node.js - PG 不会连接大的 SQL 字符串
- python-3.x - 为什么这些 if 语句在此代码中不起作用?python餐厅选择器