【问题标题】:Spring Data Rest - unable to update nested object with PUT or PATCHSpring Data Rest - 无法使用 PUT 或 PATCH 更新嵌套对象
【发布时间】:2021-01-24 01:59:16
【问题描述】:

我在 Attribute 和 AttributeGroup 之间有多对多的关系。 AttributeGroup 包含许多属性,这些属性可以是多个 AttributeGroup 的子级。 虽然 Attribute 是 AttributeGroup 的子关系,但它始终是在自己的存储库中创建的,即,它应该在 AttributeGroup 之前创建 Attribute,并且在创建 AttributeGroup 期间添加子关系时。 使用属性 repo,我可以执行所有 CRUD 操作,并使用 attributeGroup repo,成功处理 CRUD 操作。在 AttributeGroup 创建期间,与 Attribute 的关系也按预期工作。 接下来,如果我想更改关系,即删除现有属性和/或添加另一个属性,它不起作用。 我读到更新嵌套对象 PATCH 有效,但 PATCH 抛出异常

java.lang.IllegalArgumentException: Can not set java.lang.Long field Attribute.id to AttributeGroup

请告诉我这个实现有什么问题。

AttributeGroup.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class AttributeGroup implements Serializable {
    private static final long serialVersionUID = -8264102706248686536L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    String name;
    String displayName;

    @NotNull
    @Size(min = 1)
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.REFRESH})
    List<Attribute> attributes;
}

Attribute.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Attribute implements Serializable {
    private static final long serialVersionUID = 8806808817130076030L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    String name;

    String value;

    AttributeType attributeType;

    ArrayList<String> values;

    @ManyToMany(mappedBy = "attributes")
    @ToString.Exclude
    List<AttributeGroup> attributeGroups;
}

AttributeTye.java

public enum AttributeType {
    TEXT("Text Only");

    private final String attributeType;

    AttributeType(String productType) {
        this.attributeType = productType;
    }
}

【问题讨论】:

  • 我使用的补丁请求是curl --location --request PATCH 'http://localhost:8080/attributeGroups/1' --header 'Content-Type: application/json' --data-raw '{ "attributes": [ "http://localhost:8080/attributes/1", "http://localhost:8080/attributes/2", "http://localhost:8080/attributes/3" ] }'

标签: spring-data-jpa many-to-many spring-data-rest


【解决方案1】:

bidirectinoal 关系中,您需要同步关系的双方才能删除实体。

AttributeGroup 是关系的所有者。所以,它必须有一个像下面这样的方法:

public void removeAttribute(Attribute attribute){
    if(attributes.contains(attribute)){
        attributes.remove(attribute);
        attribute.getAttributeGroups().remove(this);
    }
}

另外,在Attribute 类中你应该有:

@PreRemove
void removeAttributeFromAttributeGroups(){
        for (AttributeGroup attributeGroup : attributesGroups) {
            attributeGroup.removeAttribute(this);
        }
}

同样的过程也适用于Add 操作。

【讨论】:

  • 感谢您的回复。我尝试使用您的代码和 link 进行双向处理,但我可以使用 Update 来保持数据的完整性。
  • @Senthil 正如您提供的链接(但它用于维护@OneToMany 关系)所暗示的那样,我的回答应该可以解决您的问题。如果没有,请提供更多代码,包括您可能调用的 service 方法 addAttributedeleteAttribute 方法
  • 再次感谢 Morteza。我正在使用 spring-data-rest 并且没有控制器/自定义控制器或服务类。只有实体及其相应的存储库。我正在第二次尝试和更新。代码现在有太多用于调试的日志语句,如果不起作用,我会清理并放在这里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 2018-12-23
  • 2018-05-04
相关资源
最近更新 更多