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?

0

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.

4

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy