ОШИБКА сопоставления OneToMany/ManyToOne: значение null во время сохранения таблицы «родитель — потомок»

#relational-database

Вопрос:

У меня есть две сущности:

Я понимаю, в чем проблема. FK (имя: LOGGINGEMPLOYEEMODEL_ID ) находится в таблице «loggingmodel». В момент сохранения новой записи для родительской таблицы «employeedetails» дочерняя таблица также должна быть обновлена. Но я получаю ошибку: «org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: значение NULL не разрешено для столбца «LOGGINGEMPLOYEEMODEL_ID»; Инструкция SQL: вставить в значения LoggingModel (инфотекст, loggingEmployeeModel_id, заголовок, идентификатор) (?, ?, ?, ?) [23502-199]»

Я понимаю это, новый идентификатор для записей сотрудников неизвестен для таблицы FK для детей. (Если это выведет часть «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!");
       }   
   }  

 

И вот что я делаю с Почтальоном:

 {
    "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"
        }
    ]
}

 

Может ли кто-нибудь дать представление/подсказку, что я делаю не так?

Ответ №1:

Я так понимаю, что классы моделей отображаются из JSON непосредственно на ваши сущности, верно? Если это так, то вы сталкиваетесь с двунаправленным отношением, которое устанавливается только с одной стороны. Файл unmarshalling from JSON создает новые LoggingModel экземпляры и помещает их в список. Затем он устанавливает этот список в созданном EmployeeModel экземпляре. EmployeeModel Экземпляр теперь имеет ссылку на все свои LoggingModel экземпляры. Чего все еще не хватает, так это ссылки в LoggingModel экземплярах на EmployeeModel экземпляр. JSON unmarshalling не устанавливает это, потому что он просто не знает, что это должно быть.

Быстрое решение-исправить эти ссылки самостоятельно. Быстрого ответа на каждое утверждение будет достаточно:

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