当前位置: 首页 > 知识库问答 >
问题:

Spring JPA hibernate如何从@OneToMany父列中持久化子项(删除、添加或更新)?

徐秋月
2023-03-14

我试图解决这个问题已经有一段时间了,但我还没有实现100%的解决方案。首先,我必须描述我的问题。我正在开发一个餐厅应用程序,在所有实体中,我有实体成分,正如你们所知,成分可以由特定数量的其他成分组成。所以我创建了一个实体子成分,带有一个嵌入的Id。

为了保留子成分列表,我尝试了级联和去除孤儿的组合,每种组合对某些操作有效,但对其他操作无效。

我从使用CascadeType开始。所有和新的子成分成功地从@OneToMany属性中保留,但如果我试图从子成分列表中删除子成分并保存,则会出现此错误。

JAVAlang.StackOverflower错误:在com上为空。mysql。希杰。民族复兴。execSQL(NativeSession.java:1109)~[mysql-connector-java-8.0.23.jar:8.0.23]。。。。。。

我在网上登录了一个解决方案,我发现我必须使用孤儿移除=true我试过了,但是它不起作用,直到我把级联从CascadeType. ALL改为CascadeType. PERSIST。但是这一个使得新的子成分的持久性这个错误提前

原因:javax。坚持不懈EntityNotFoundException:找不到com。实例雷斯托。领域id为com的子成分。实例雷斯托。领域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...

共有2个答案

左丘照
2023-03-14

感谢Pilpo,我对may实体进行了一些更改,并重写了equals/hashcode方法,从而解决了这个问题。

@Embeddable
public class SubIngredientKey implements Serializable{


private Long ingredientId;


private Long subIngredientId;
/**
 * @return the ingredientId
 */


@Override
public int hashCode() {
    return Objects.hash(ingredientId, subIngredientId);
}
@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (!(obj instanceof SubIngredientKey)) {
        return false;
    }
    SubIngredientKey other = (SubIngredientKey) obj;
    return Objects.equals(ingredientId, other.ingredientId)
            && Objects.equals(subIngredientId, other.subIngredientId);
}

}



@Entity
public class SubIngredient {


@EmbeddedId
private SubIngredientKey embId = new SubIngredientKey();

@ManyToOne(fetch = FetchType.LAZY)
@MapsId("ingredientId")
private Ingredient ingredient;

@ManyToOne(fetch = FetchType.LAZY)
@MapsId("subIngredientId")
private Ingredient subIngredient;

private double quantity;

@JsonIgnore
public SubIngredientKey getId() {
    return embId;
}
public void setId(SubIngredientKey id) {
    this.embId = id;
}


@JsonIgnoreProperties({"subIngredients","photo","photoContentType","ingredientType"})
public Ingredient getIngredient() {
    return ingredient;
}
public void setIngredient(Ingredient ingredient) {
    this.ingredient = ingredient;
}



@JsonIgnoreProperties({"subIngredients","photo","photoContentType","ingredientType"})
public Ingredient getSubIngredient() {
    return subIngredient;
}
public void setSubIngredient(Ingredient subIngredient) {
    this.subIngredient = subIngredient;
}

public double getQuantity() {
    return quantity;
}

public void setQuantity(double quantity) {
    this.quantity = quantity;
}

@Override
public String toString() {
    return "subIngredient= " + getSubIngredient().getName() + " , quantity=  " + getQuantity();
}


@Override
public int hashCode() {
    return Objects.hash(ingredient,subIngredient);
}
@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (!(obj instanceof SubIngredient)) {
        return false;
    }
    SubIngredient other = (SubIngredient) obj;
    return Objects.equals(ingredient, other.ingredient) && Objects.equals(subIngredient, other.subIngredient);
}

}



@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, orphanRemoval = true)
private Set<SubIngredient> subIngredients =  new HashSet<SubIngredient>();



public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

public String getPhotoContentType() {
    return photoContentType;
}



public void setPhotoContentType(String photoContentType) {
    this.photoContentType = photoContentType;
}

public byte[] getPhoto() {
    return photo;
}

public void setPhoto(byte[] photo) {
    this.photo = photo;
}


public IngredientType getIngredientType() {
    return this.ingredientType;
}
public void setIngredientType(IngredientType ingredientType) {
    this.ingredientType = ingredientType;
}



public Set<SubIngredient> getSubIngredients() {
    return subIngredients;
}

public void setSubIngredients(Set<SubIngredient> subIngredients) {
    this.subIngredients = subIngredients;
}

public void addSubIngredient(SubIngredient subIngredient) {
    this.subIngredients.add(subIngredient);
}

@Override
public String toString() {
     String subIngsText = "";
     for(var subIngredient:this.subIngredients) {
         subIngsText = subIngsText + ", " +  subIngredient.toString();
     }
    return "{id= "+id+",name=" + name +", ingredients="+subIngsText+"}";
}

@Override
public int hashCode() {
    
    return Objects.hash(name);
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (!(obj instanceof Ingredient)) {
        return false;
    }
    Ingredient other = (Ingredient) obj;
    return Objects.equals(name, other.name);
}
}
丰博
2023-03-14

stackoverflow之所以发生,是因为您使用了集合

hashcode Ingredient -> hashcode SubIngredient -> hashcode Ingredient 

这将导致无限次调用hashcode方法。这就是为什么会出现堆栈溢出错误

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

因此,为了避免这样的问题,最好重写hashcode等于toString

 类似资料:
  • 我已经创建了纸张和Mcq问题之间的映射如下。 } 当我更新纸质实体时,它会删除所有MCQ。 SQL输出:

  • 问题内容: 我有以下实体: 球队 } 和 USER_TEAM_ROLE 现在,当使用{UTR1,UTR3}更新包含例如Team.userTeamRoles = {UTR1,UTR2}的Team实体时,我希望删除UTR2。但是我现在的方法是,旧列表保持不变,并且只将UTR3添加到列表中。 这是我目前的做法: 我认为通过执行该列表将被重置,并且由于级联,先前的列表将被删除。 任何帮助表示赞赏。谢谢 问

  • 问题内容: 从列表中删除项目时遇到麻烦。该列表是在超类中定义的,但是Hibernate批注将应用于子类中的属性访问器。超类中有两种方法可以操作列表。“添加”方法可以正常工作,但“删除”不能持久保存更改。我检查了我的Cascade设置,似乎一切正确。我在做一些不可能的事情吗?如果不是,我做错了什么吗? 这是我的课程: 我按如下方式使用TemporalAsset类的实例(请注意,我仅使用“refres

  • 问题内容: 我做了一个具有更多关系的小型应用程序。现在,我想删除表格的详细信息,如何删除我没有删除任何想法。 关系如下: PanCard->员工(Ono To One) Employee-> ProjectManger(与员工的双向多对一关联) 项目-> ProjectManager(与项目的双向多对一关联) 现在我要删除一张一张的表数据 以下是我的POJO类代码: PanCard.java Em

  • 我正在创建一个新项目,并使用Spring Data JPA创建一些RESTendpoint。 只要json文件没有任何oneToMany数据,我就可以将其放到并持久化到我的主类(customer)中。然而,当张贴给客户,如果有任何数据,我会得到错误。 那些电子邮件 postman json测试 顺便说一句,我已经确认在客户控制器中,电子邮件包括在客户的请求体中。 客户控制器 因此,对于post或p

  • 问题内容: 我在Hibernate中有标准协会。更新时,我正在创建新实体(使用关键字),并用必要的值(还插入ID)填充它。值来自UI。以相同的方式,我创建了子对象的新集合,用值(也插入了ID)填充每个子对象,并将集合存储在父对象中(使用setter或按方法)。 所以我的问题是:如何在更新父级时删除父级集合中的所有对象,并用新的集合替换它们。在新集合中,某些对象确实是新对象,而某些对象仅需要更新(它