'Only allow updating JPA entity when @version attribute matches

I have two classes, a file and an attachment. There is a version attribute on the file and it has a onetomany relationship. I have written code to upload/add attachments to the file. The code works.

However, It doesn't look at the version attribute of 'File' and updates the entity anyway. I would like to add versioning to be checked when calling the addAttachment method. I've tried providing the current value as a requestparam and set it on the File, however, this is not being checked. Any advice on how to setup the controller to make versioning work?

Classes:

....    
@Data
public class File {
    @Id
    private Long fileId;
    @Version
    private Long tstamp;
    @OneToMany(cascase = CascadeType.All)
    @JoinColumn(name = "fileId", referencedColumnName = "fileId")
    private List<Attachment> attachments = new ArrayList<>();
    
    ....
    
    public void addAttachment(Attachment attachment) {
        attachments.add(attachment);
    }
}

@Data
public class Attachment {
    @Id
    private Long attachmentId;
    private String ....;
    
    ......
}

FileService to add attachment to file:

@Transactional
public File addAttachmentToFile(Long id, Long tstamp, Long attachmentId) {
    File fileCurrent = getFileById(id);
    fileCurrent.setTstamp(tstamp);
    Attachment attachment = attachmentService.getAttachmentById(attachmentId);

    fileCurrent.addAttachment(attachment);
    File file = saveFile(fileCurrent);
    return file;
}

File controller:

@PostMapping("/{fileId}/attachments")
public ResponseEntity<File> addAttachmentToFile(@PathVariable final Long fileId, @RequestParam("version") Long tstamp, @RequestParam("attachments") MultipartFile attachment) {
    Attachment createdAttachment = attachmentService.saveAttachment(attachment);
    Long attachmentId = createdAttachment.getAttachmentId();
    fileService.addAttachmentToFile(finDocId, tstamp, attachmentId);
    File file = fileService.getFileById(fileId);
    return new ResponseEntity<>(file, HttpStatus.OK);
}


Solution 1:[1]

I learned that:

By default, the child or to-many relationship site owns the one-to-many association. Therefore, Hibernate doesn’t increment the version number of the parent entity when you add or remove a child entity.

But you can use the LockModeType.OPTIMISTIC_FORCE_INCREMENT to trigger the version update programmatically.

You can choose between 2 options to set the LockModeType for a specific entity. You either call the lock method on the EntityManager or perform a JPQL query and provide the LockModeType.OPTIMISTIC_FORCE_INCREMENT to the setLockMode method.

You could refer to Hibernate Tips: How to Increase the Version of the Parent Entity When Updating a Child Entity for the in-detail tutorial.

There's one more way you could try to achieve version update i.e. using Event Listeners. It also intercepts any child entity modification and acquires an OPTIMISTIC_FORCE_INCREMENT event on the associated root entity.

I think this method might be an optimal solution. You can follow How to increment the parent entity version whenever a child entity gets modified with JPA and Hibernate for the in-detail tutorial.

One more comment: I notice that you've set tstamp as version but I don't think the version is actually set as timestamps. They're usually like auto-increment that just increment by 1.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Keshavram Kuduwa