Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?
I usually solve this in the service layer.
You can read the entity you want to update from the DB, and overwrite the attributes which you are getting from your form.
This way you change only the attributes you want.
Code example:
@Service
@Transactional
public class UserService {
@Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
public void mergeWithExistingAndUpdate(final Person personFromPost) {
Session session = sessionFactory.getCurrentSession();
Person existingPerson = (Person) session.get(Person.class, personFromPost.getId());
// set here explicitly what must/can be overwritten by the html form POST
existingPerson.setName(personFromPost.getName());
existingPerson.setEmail(personFromPost.getEmail());
existingPerson.setDateModified(new Date());
existingPerson.setUserModified(Utils.getCurrentUser());
session.update(existingPerson);
}
}
EDIT 1
There is in fact a Spring-way to solve this issue, using @SessionAttributes
, see this anwer:
https://stackoverflow.com/a/3675919/272180
I did not yet test it, but it looks promising.
EDIT 2
Eventually I tested it and it works as expected.
There is one thing however which can make you shoot in your foot:
If you open several tabs with the same form, the opening of the last tab overwrites the sessionAttribute
of the others, and, on submit, can potentially corrupt your data. There is a solution in this blog post: http://marty-java-dev.blogspot.com/2010/09/spring-3-session-level-model-attributes.html
But at the end, if you never open multiple tabs for editing, you will not have a problem anyway.
If you never want to update a particular attribute, you can mark it with updatable=false
:
@Column(name="CREATED_ON", updatable=false)
private Date createdOn;
Once you load an entity and you modify it, as long as the current Session
or EntityManager
is open, Hibernate can track changes through the dirty checking mechanism. Then, during flush
, an SQL UPDATE will be executed.
If you don't like that all columns are included in the UPDATE
statement, you can use dynamic update:
@Entity
@DynamicUpdate
public class Product {
//code omitted for brevity
}
Then, only the modified columns will be included in the UPDATE
statement.