Spring-Boot JPA - вставка в БД с внешними ключами в JSON RequestBody приводит к нулевому объекту

Я пытаюсь сохранить записи в таблицу базы данных, которая включает внешний ключ в другую таблицу, используя Spring-Boot и Spring Data JPA.

Мой JSON выглядит так:

{
    "requestId": 10080,
    "auditType": "C",
    "auditDate": "2019-06-12T17:25:43.511",
    "auditUsername": "cdunstal",
    "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget porttitor velit. Fusce libero augue, tincidunt in vestibulum nec, lobortis tristique eros. Cras tempor est magna, eu dapibus metus bibendum non.",
    "isReportable": "Y"
}

Моя сущность выглядит так:

@Entity
@Table(name = "CHANGE_AUDIT")
@SequenceGenerator(name = "CHANGE_AUDIT_PK_SEQ", sequenceName = "CHANGE_AUDIT_PK_SEQ", allocationSize = 1)
public class ChangeAudit {

    @Column(name = "AUDIT_ID")
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHANGE_AUDIT_PK_SEQ")
    private Integer id;

    @Version
    private Long version;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REQUEST_ID")
    @NotNull
    private ChangeRequest changeRequest;

    @Column(name = "AUDIT_TYPE", nullable = false, length = 1)
    @NotNull
    @Size(max = 1)
    private String auditType;

    @Column(name = "AUDIT_DATE", nullable = false)
    @NotNull
    private Date auditDate;

    @Column(name = "AUDIT_USER", nullable = false, length = 10)
    @NotNull
    @Size(max = 10)
    private String auditUsername;

    @Column(name = "AUDIT_MESSAGE", nullable = false, length = 4000)
    @NotNull
    @Size(max = 4000)
    private String message;

    @Column(name = "IS_REPORTABLE", nullable = false, length = 1)
    @NotNull
    @Size(max = 1)
    private String isReportable;

    // Constructor, getters and setters omitted.
}

Мой метод контроллера:

@RequestMapping(value = "/changeAudit/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody()
public ChangeAudit createChangeAudit(@RequestBody ChangeAudit changeAudit) {
    logger.info("Creating new ChangeAudit: " + changeAudit.toString());
    return this.changeAuditService.createChangeAudit(changeAudit);
}

Я получаю следующую ошибку:

{
    "timestamp": 1560412164364,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "org.springframework.transaction.TransactionSystemException",
    "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction",
    "path": "/grade-admin-api/changeAudit/create"
}

Что вызвано:

Caused by: javax.persistence.RollbackException: Error while committing the transaction
        at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:87)
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
        ... 78 common frames omitted
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [au.edu.csu.gradeadmin.api.entity.ChangeAudit] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
        ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=changeRequest, rootBeanClass=class au.edu.csu.gradeadmin.api.entity.ChangeAudit, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]

Таким образом, при сохранении ChangeAudit он не берет requestId из JSON и не переводит его в объект ChangeRequest в Entity.

Кажется, я не могу найти какую-либо документацию, учебник или любой другой вопрос о переполнении стека, который решает мою проблему. Я пытался использовать другой класс в качестве @RequestBody, но он просто возвращает нулевые значения. Я застрял на этом в течение двух дней, и мне нужно его пройти, поэтому буду признателен за любую помощь, которую кто-либо может предложить.

Простите за краткость, пришлось поторопиться с публикацией. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Спасибо.

Обновление – ответ

@ user06062019 поставил меня на правильный путь. Я исправил отправленный JSON и добавил CascadeType.ALL в Entity, однако это дало мне другую ошибку: я не мог вставить null в ChangeRequest.pidm.

Это связано с тем, что у меня был requestId в качестве внешнего ключа в отправленном JSON, однако он должен был быть просто идентификатором, как называется параметр в классе ChangeRequest. Затем я мог бы получить класс ChangeRequest в ChangeAuditService, добавить его в объект ChangeAudit и сохранить. Вуаля!

Правильный JSON:

{
    "changeRequest": {
        "id": 10080 
    },
    "auditType": "C",
    "auditDate": "2019-06-12T17:36:43.511",
    "auditUsername": "someuser",
    "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget porttitor velit. Fusce libero augue, tincidunt in vestibulum nec, lobortis tristique eros. Cras tempor est magna, eu dapibus metus bibendum non.",
    "isReportable": "Y"
}

Не могли бы вы опубликовать метод, как сохранить объект. Исключение говорит, что changeRequest не должен быть нулевым. Возможно, вам потребуется установить объект changeRequest для объекта перед сохранением.

user06062019 13.06.2019 10:11

Либо ChangeRequest уже должен существовать в БД, либо вам нужно получить объект ChangeRequest и установить его в ChangeAudit перед сохранением.

Suresh 13.06.2019 11:58

@Suresh Я знаю, это то, чего я не могу достичь. Я не могу понять, как получить объект ChangeAudit из внешнего ключа (requestId)

Cyntech 13.06.2019 12:35

@ user06062019 Я еще не написал класс ControllerAdvice. Ошибка возникает из-за встроенной обработки/проверки ошибок из аннотации @NotNull в Entity. –

Cyntech 13.06.2019 12:41

@Cyntech печатает changeAudit.toString() requestId? Создайте репозиторий ChangeRequest, который представляет ваш объект ChangeRequest. Если requestId имеет значение null, это означает, что объект не существует в базе данных и может обработать ошибку. В другом случае, когда requestId не равен нулю, вызовите findById репозитория ChangeRequest и получите объект объект, установите этот объект объекта в ChangeAudit.

user06062019 13.06.2019 13:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
5
4 903
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кажется, есть проблема в json, который вы отправляете в

createChangeAudit

Объект ChangeAudit ожидает тип объекта для запроса на изменение, и этот тип объекта отсутствует в запросе json.

Поэтому, если вы измените свой запрос на что-то подобное, он не должен жаловаться на ошибку проверки, а об остальном позаботится spring-data automagic.

{

    "auditType": "C",
    "auditDate": "2019-06-12T17:25:43.511",
    "auditUsername": "cdunstal",
    "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget porttitor velit. Fusce libero augue, tincidunt in vestibulum nec, lobortis tristique eros. Cras tempor est magna, eu dapibus metus bibendum non.",
    "isReportable": "Y",
    "changeRequest":{
        "requestId": 10080
    }


}

Также вам может понадобиться упомянуть о сопоставлении @ManyToOne с cascade= CascadeType.ALL

Другие вопросы по теме