首页 > 解决方案 > ERROR OneTOMany/ManyToOne 映射:保存父子表时为空

问题描述

我有两个实体:

我明白这个问题。FK(名称:LOGGINGEMPLOYEEMODEL_ID)在表“loggingmodel”中。在为父表“employeedetails”保存新记录时,子表也应该更新。但我收到错误消息:“org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "LOGGINGEMPLOYEEMODEL_ID"; SQL 语句:插入 LoggingModel (infotext, loggingEmployeeModel_id, title, id) 值 (?, ?, ?, ?) [ 23502-199]"

我明白了,对于子表的 FK,employeedetails 的新 ID 是未知的。(如果它从 Postman 注入中取出“employeeModelLogging”部分,那么我不会得到约束错误,所以它应该是 loggingModel 部分)

如何在 JPA - Hibernate 中解决这个问题?

父方:一对多:


@Entity
@AllArgsConstructor    
@Getter
@Setter
@NoArgsConstructor     
@Table(name="employeedetails", schema="public")
public class EmployeeModel implements Serializable {        
 
    private static final long serialVersionUID = -3009157732242241606L;
     
    @Id
    @Column(name="id")
    @SequenceGenerator(initialValue=1, name="employeedetails_seq", sequenceName="employeedetails_sequence", allocationSize=1)
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="employeedetails_seq")
    private Long id;
        ...
     
    @OneToMany(mappedBy = "loggingEmployeeModel",fetch=FetchType.LAZY , cascade = CascadeType.ALL)
        private List<LoggingModel> employeeModelLogging;
     
       ...
  
}

子方:多对一:

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class LoggingModel {
 
    @Id
    @Column(name = "id")
    @SequenceGenerator(initialValue = 1, name = "log_seq", sequenceName = "log_sequence", allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "log_seq")
    private Long id;
    @Column() 
    private String title;
    @Column()
    private String infotext;
     
    @ManyToOne (cascade = CascadeType.ALL)
    @JoinColumn(name = "loggingEmployeeModel_id", referencedColumnName = "id", nullable = false) 
    private EmployeeModel loggingEmployeeModel;
     
}

创建员工服务实现:


       @Override
   public ResponseEntity<Object> createEmployee(EmployeeModel employeeModelToCreate) {
        
       if (employeeRepository.findByEmployeeName(employeeModelToCreate.getEmployeeName()).isEmpty()) {
        
           employeeModelToCreate.setCreatedDateTime(LocalDateTime.now());
           employeeModelToCreate.setModifiedDateTime(LocalDateTime.now());
 
           Long unitId = employeeModelToCreate.getUnit().getId();
           Unit unit = em.find(Unit.class, unitId);
           employeeModelToCreate.setUnit(em.getReference(Unit.class, unitId)); // Alternative 2
                
           EmployeeModel savedEmployeeModel = employeeRepository.save(employeeModelToCreate);
            
           if (employeeRepository.findById(savedEmployeeModel .getId()).isPresent())
                return ResponseEntity.ok("User Created Successfully");
            else
                return ResponseEntity.unprocessableEntity().body("Failed Creating User as Specified");
       } else {
           return ResponseEntity.unprocessableEntity().body("msg: Employee with this employee name: " + employeeModelToCreate.getEmployeeName() + ", already exist in DB!");
       }   
   }  

这就是我用 Postman 注入的内容:

{
    "employeeName": "Nico",
    "employeeCode": "ECN0004",
    "designation": "ZZZZZ",
    "address": {
        "doorNumber": "37",
        "street": "Laakse Laan",
        "city": "Zutphen"
    },
    "department": {
        "deptName": "Nieuwegein"
    },
    "employeeModelLogging":[
        {
            "title": "Dit is de titel - nieuw opmerking",
            "infotext": "Dit is de infotext "
        },
        {
            "title": "Dit is de titel van de 2e opmerking ",
            "infotext": "Dit is de infotext van de 2e opmerking"
        }
    ],
    "unit":  {
        "id": 3
    },
    "roles": [
        {
            "id": 1,
            "name":"Admin",
            "description": "Administrator"
        },
        {
            "id": 2,
            "name":"Guest",
            "description": "Gast"
        }
    ]
}

有人可以给出一个想法/提示我做错了什么吗?

标签: relational-database

解决方案


我认为模型类是从 JSON 直接映射到您的实体的,对吗?如果是这样,您将遇到仅在一侧设置的双向关系。unmarshallingfrom JSON 创建新实例LoggingModel,并将它们放入列表中。EmployeeModel然后它在创建的实例上设置该列表。该EmployeeModel实例现在具有对其所有LoggingModel实例的引用。仍然缺少的是LoggingModel实例中对实例的EmployeeModel引用。JSONunmarshalling没有设置它,因为它根本不知道它应该这样做。

一个快速的解决方案是自己修复这些引用。一个快速的 for-each 语句就足够了:

employeeModel.getEmployeeModelLogging().forEach(lm -> lm.setLoggingEmployeeModel(employeeModel);

推荐阅读