Spring-Boot JPA - Inserting into DB with foreign k

2019-08-12 01:19发布

问题:

I'm attempting to save records to a database table that includes a foreign key to another table using Spring-Boot and Spring Data JPA.

My JSON looks like this:

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

My Entity looks like this:

@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.
}

My Controller method is:

@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);
}

I receive the following error:

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

Which is caused by:

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}'}
]

So, when saving the ChangeAudit, it's not taking the requestId from the JSON and translating that to the ChangeRequest object in the Entity.

I can't seem to find any documentation or tutorial or any other stack overflow question that solves my problem. I have tried using a different class as the @RequestBody but it just comes back with null values. I've been stuck on this for two days and need to get passed it, so would appreciate any assistance anyone might be able to offer.

Forgive the brevity, I had to rush the posting. Please let me know if you need more info.

Thanks.

Update - Answer

@user06062019 put me on the right track. I corrected the submitted JSON and added the CascadeType.ALL to the Entity, however, this gave me a different error - that I couldn't insert null into ChangeRequest.pidm.

This is because I had requestId as the foreign key in the submitted JSON, however, it needed to be just id, which is what the parameter in the ChangeRequest class is called. I could then retrieve the ChangeRequest class in the ChangeAuditService, add it to the ChangeAudit object and save it. Voila!

Correct 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"
}

回答1:

It seems there is issue in the json which you are sending to the

createChangeAudit

The ChangeAudit object expects an object type for the ChangeRequest and that object type is missing in the request json.

So if you change your request to something like this it should not complain about the validation error and rest will be taken care by the 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
    }


}

Also you might need to mention on @ManyToOne mapping with cascade= CascadeType.ALL