How to update only particular fields in an entity using springbooot JPA update API
This is not really springboot jpa problem. The issue is in the way updateBook
method in service has been implemented. The updateBook
method is setting all the fields from dto
on persisted book entity without checking if the dto.get*
returns null or not.
Very simply but crude solution to this problem would be to have if(dto.get* != null)
check for each field before setting the value in book entity. i.e.
if (bookDto.getBookAuthor() != null)
book.setBookAuthor(bookDto.getBookAuthor());
if (bookDto.getBookLanguage() != null)
book.setBookLanguage(bookDto.getBookLanguage());
if (bookDto.getBookPrice() != 0)
book.setBookPrice(bookDto.getBookPrice());
...
This leaves the updateBook
service method generic to allow updating one or more fields without worrying about others being overwritten. If this makes your service method too noisy the dto to entity conversation part can be extracted into its own method for clarity.
For more advance usecases and if your entity/dto has more than a handful fields or nested objects as fields then this becomes cumbersome. In such scenarios you may want to handcraft a separate implementation which perhaps uses reflection to map fields from dto to entity if the field value is not null. The usage of reflection is however likely to be slow and/or error prone if not done properly.
There are however libraries and frameworks for more regular usecases which makes such conversation easier. At the simplest springframework's BeanUtils.copyProperties method provides a way to map values from one object to another and the last argument of ignored properties can be used to provide fields names to be ignored. This stackoverflow answer shows how to write a generic method that creates a list of property names to ignore if they are null in source object; and they uses this list to pass as parameter in BeanUtils.copyProperties
.
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<>();
for(PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
return emptyNames.toArray(new String[0]);
}
then in your service method;
Book book = bookRepository.findById(bookDto.getBookId())
.orElseThrow(() -> new DataNotFoundException("Book not found"));
BeanUtils.copyProperties(bookDto, book, getNullPropertyNames(bookDto));
bookRepository.save(book);
For further advanced usecases you can use frameworks such as mapstruct or modelmapper.
How to update only specific field with spring jpa repository?
I have a below Student entity and I want to update only not null
fields when I call CrudRepository save method.
You can't do this in this way because when you provide an entity to Spring or JPA for an update operation, they cannot guess why some fields of this entity are null : is it null
because you want to set the field to null ? Or is is null
because you have not fulfilled this field but you don't want that the existing value to be overwritten ?
So, they don't make guesworks and simply update the row with effective values in the fields of your entity.
So you should write a JPQL Query where you explicit fields to update :
UPDATE Student e SET e.name=%1 AND e.number=%2
WHERE ...
Updating one field in JPA entity
Do I need to do a findById then update the specific field then do the merge
That would be the regular approach, except that you don't need to merge a managed entity, just let JPA detect the changes and update it automatically.
or is there a way to tell the to only update that field?
No. But you could use a "short" version of your User
(with only the field(s) to update). Another option would be to use a Bulk Update Operation but this is IMO really not a good use case. I wouldn't use this approach.
Reference
- JPA 1.0 specification
- 4.10 Bulk Update and Delete Operations
Related Topics
Calculate the Number of Items Displayed by Recyclerview and Place in a Textview
How to Query Using an Enum Parameter Mapped as Ordinal Using JPA and Hibernate
Ldap Query Get All Groups (Nested) of a Group
Java:How to Determine the Correct Charset Encoding of a Stream
Missing Method Body, or Declare Abstract in Java
How to Run Multiple Jobs in Spring Batch Using Annotations
How to Modify a Field in Each Element of List in Java 8 Using Stream
Could Not Open JPA Entitymanager for Transaction (Using Localcontainerentitymanagerfactorybean)
How to Fix: Error Creating Bean With Name:Unsatisfied Dependency Expressed Through Field
Java - Replace New Line Character by \N
How to Download a File from S3 Using Provided Url
How to Return Different Types of Responseentity in Spring MVC or Spring-Boot
How to Write Multiple Line Property Value Using Propertiesconfiguration
Java Package Does Not Exist Error
How to Launch Command in Batch File With Space