Spring 使用 JSON RequestBody 引导保存嵌套实体

Spring Boot save nested Entity with JSON RequestBody

我正在尝试为学校创建一个 Rest API project.Therefor 我正在尝试 save/edit 一个嵌套对象。 我有两个双向实体,如下所示:

实体A

 @Entity
    public class EntityA {
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Id
        @Column(name = "id", nullable = false)
        @JsonProperty("id")
        private int id;
    
        @Column(name = "field1", nullable = false, length = -1)
        @JsonProperty("field1")
        private String field1;
    
        @Column(name = "field2", nullable = false, length = -1)
        @JsonProperty("field2")
        private String field2;
    
        @OneToMany(mappedBy = "entityA", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
        @JsonProperty("entityB")
        private List<EntityB> entityB;
    
        public EntityA() {
    
        }
        
        //Getter+Setter
        
    }

实体B

@Entity
public class EntityB {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", nullable = false)
    @JsonProperty("id")
    private int id;

    @Column(name = "field1", nullable = false)
    @JsonProperty("field1")
    private Date field1;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(...)
    @JsonProperty("entityA")
    private EntityA entityA;

    public EntityB() {

    }
    
   //Getter+Setter
}

作为 RequestBody,我将得到 JSON,它应该看起来像这样。

{
     "field1": "Test",
     "field2": "User",
     "entityB": [
            {
                "field1": "30.03.2022"
            }
        ]
}

现在 Spring 将自动映射字段,但是一旦我尝试将其保存到我的数据库中,我就会收到错误消息,因为 EntityBEntityA 的关系是空的。 我看到了一个解决方案,我应该遍历 EntityB 列表并添加 EntityA。我用 for-each 尝试了它,但它仍然说它是空的。

我做错了什么?

public EntityA createEntityA(EntityA entityA) {
        for(EntityB entityB : entityA.getEntityB()){
            entityB.setEntityA(entityA);
        }
        return entityARepository.save(entityA);
    }

编辑:

控制器

@PostMapping(value = {"/json/entitya/"})
@ResponseBody
public EntityA createEntityAJson(@RequestBody EntityA entityA) {
    return entityAService.createEntityA(entityA);
}

服务

@Service
public class EntityAService {

    @Autowired
    private EntityARepository entityARepository;

    public EntityA createEntityA(EntityA entityA) {
        return entityARepository.save(entityA); //in this line the error appears
    }
}

错误信息

null value in column "entityA" violates not-null constraint

我猜这里发生的是 non-nullable 数据类型的 id 字段或 JPA 注释中的一些其他隐藏字段被 json 反序列化让 JPA 了解它们是新实体。在 Java 代码中手动创建这些实体可能会解决问题。

您不应将实体 类 重新用作 API 的数据传输对象。让 类 同时包含 database-specific 注释和 JSON 序列化的注释是一个坏主意,它违反了 single-responsibility 原则 (SRP)。

为您的 API 端点创建单独的 DTO 类,然后从数据库中读取实体并在保存之前将 DTO 对象中的值复制到实体。

// Receive DTO
// Read entity from DB if update or create new entities if insert
// Copy values from DTO to entitiy
// Save entity

我想如果你应用这个模式,你的问题就会消失。

@Service
public class EntityAService {
    
        @Autowired
        private EntityARepository entityARepository;
        @Autowired
        private EntityBRepository entityBRepository;
    
        public EntityA createEntityA(EntityA entityA) {

      // create an empty arrayList to stock the entities B retrieveed from the DB
       List<EnityB> lst = new ArrayList<>();
        
        // get the entities B from the JSON and sabe it to the DB    
        for(EntityB entityB : entityA.getEntityB()){
        entityB.setEntityA(entityA);
        entityBRepository.save(entityB);  // you should save entities B to the DataBase before
        Optional<EntityB > opt = entityBRepository.findById(entityB.getId());
        EntityB b = opt.get();
        
        // add the entities B retrieved from the DB to the arrayList
        lst.add(b);
        }
        
        // set the EntityB list with the new List from the DB ( include ids ..)
        entityA.setEntityB(lst);
         
        // save the entityA to the DB
            return entityARepository.save(entityA); 
        }
    }