I am using spring data-jpa. I want update only one column.
My repository is;
public interface UserRepository extends JpaRepository<User,Long> { } my Service is;
public User save(User user) { return userRepository.save(user); } my Entity;
@Entity @DynamicUpdate(true) public class User implements Serializable { // column definitions, etc. } How can I update only one column in User?
2 Answers
First of all I want to explain why @DynamicUpdate is not working for you. So I should notice how @DynamicUpdate works:
The @DynamicUpdate annotation is used to specify that the UPDATE SQL statement should be generated whenever an entity is modified. By default, Hibernate uses a cached UPDATE statement that sets all table columns. When the entity is annotated with the @DynamicUpdate annotation, the PreparedStatement is going to include only the columns whose values have been changed.(more details)
For example assume that User has a property called name.
So if for the first time you saved user with a defined name, now you are passing null as the value @DynamicUpdate will assume it as a change and trying to update name to null.
First solution:
As the first solution, if you want @DynamicUpdate works, first you should fill all other User properties with old values, then you can save it.
Pros: The generated SQL query just updates the property you want.
Cons: Hibernate has to generate the corresponding SQL string each time and there is thus a performance cost on the Hibernate side.
Second solution:
You can update User with custom query:
@Modifying @Query("UPDATE User SET name=(:name) WHERE id=(:id)") public void updateName(@Param("name")String name, @Param("id")Long id); Third solution:
As the last solution I can suggest you to use updatable = false. This will fill the property on the very first moment the entity inserted.
@Column(name = "create_date", nullable = false, updatable = false) private Instant createDate; Your problem is due to your passing of an entirely new User entity hence Hibernate cannot use a cached version that has been already fetched from database and decide which columns to update dynamically.
So, try to do the following to confirm the correct behaviour of @DynamicUpdate;
In service;
@Transactional public User save(User newUser) { User currentUser = userRepository.get(newUser.getId()); // handle merging of updated columns onto currentUser manually or via some mapping tool currentUser.setName(newUser.getName()); return userRepository.save(currentUser); } With the above logic, together with dynamic update annotation, you should be able to see the update of only name column, unless you have some audit enabled, or using @Version'ed column.
If the updated columns are always same, then it is better to use updatable = false for the columns that are not target for the update in their @Column definitions, for using @DynamicUpdate is very inefficient since it generates each sql anew, never utilizing cached sqls. But beware using this feature, since you will be unable to update these columns at all.
I don't recommend using @Query unless you have a case where native JPA/Hibernate is insufficient, but if you have a use-case to update a target set of columns only, it is the best choice, and the most efficient.
If the updated columns are many and can vary greatly, either define a manual mapping logic between newUser to the currentUser, or utilize some mapping tools such as Orika, I have a similar automated structure where hundreds of entities are patched through these mappers, allowing an extremely generic way to handle many CRUD operations.