首页 > 解决方案 > Spring JPA休眠如何从@OneToMany父列中持久化子项(删除、添加或更新)?

问题描述

我一直在尝试解决这个问题,但我还没有达到 100% 的解决方案。首先,我必须描述我的问题。我正在开发一个餐厅应用程序,在实体中,我有实体成分,并且如您所知,成分可以由具有特定数量的其他成分组成。所以我创建了一个带有嵌入式 ID 的实体子成分。

为了坚持 subIngredients 列表,我尝试了 Cascade 和 orphanRemoval 的组合,每种组合都适用于某些操作,但不适用于其他操作。

我从使用 CascadeType.ALL 开始,并且新的 subIngredient 从 @OneToMany 属性中成功保留,但是如果我尝试从 subIngredients 列表中删除 subIngredient 并保存此错误,则会出现。

java.lang.StackOverflowError: null at com.mysql.cj.NativeSession.execSQL(NativeSession.java:1109) ~[mysql-connector-java-8.0.23.jar:8.0.23]......

我在网上寻找一个解决方案,我发现我必须使用 orphanremoval = true 我试过了,但是直到我将级联从 CascadeType.ALL 更改为 CascadeType.PERSIST 后它才起作用。但是这使得新的 SubIngredient 的持久性出现了这个错误

引起:javax.persistence.EntityNotFoundException:无法找到 com.example.Resto.domain.SubIngredient id 为 com.example.Resto.domain.SubIngredientKey@51b11186 ......

这些是我的实体:

@Entity
public class Ingredient {

@Id
@GeneratedValue( strategy = GenerationType.IDENTITY)
@Column(name="ID")
private long id;


@NotNull
@Column(unique=true)
private String name;
private String photoContentType;
@Lob
private byte[] photo;

@JsonIgnoreProperties({"photoContentType","photo"})
@ManyToOne
private IngredientType ingredientType;


@OneToMany(mappedBy = "embId.ingredientId", fetch = FetchType.EAGER,   
cascade = CascadeType.ALL /*or orphanRemoval = true, cascade = CascadeType.PERSIST*/ )
private Set<SubIngredient> subIngredients =  new HashSet<SubIngredient>();

getters and setters.....

@Entity
@AssociationOverrides({
@AssociationOverride(name = "embId.ingredientId", 
    joinColumns = @JoinColumn(name = "ING_ID")),
@AssociationOverride(name = "embId.subIngredientId", 
    joinColumns = @JoinColumn(name = "SUB_ING_ID")) })
public class SubIngredient {


@EmbeddedId
private SubIngredientKey embId = new SubIngredientKey();

private double quantity;

getters and setters....

@Embeddable
public class SubIngredientKey implements Serializable{

@ManyToOne(cascade = CascadeType.ALL)
private Ingredient ingredientId;


@ManyToOne(cascade = CascadeType.ALL)
private Ingredient subIngredientId;

getters and setters...

标签: springhibernatejpa

解决方案


发生这种stackoverflow情况是因为您使用了Set<>with Hibernate。当Hibernate从您的数据库中检索实体时,它将填充Set<>每个实体。为此,hashode/equals将用于确定实体是否已经存在于Set<>. 默认情况下,当您调用成分的哈希码时,会发生这种情况:

hashcode Ingredient -> hashcode SubIngredient -> hashcode Ingredient 

这将导致方法的无限调用hashcode。这就是为什么你有一个stackoverflow error.

同样的事情也会发生equals/toString

所以为了避免这样的问题,最好覆盖hashcode,equalstoString.


推荐阅读