Spring data : CrudRepository's save method and update
Asked Answered
L

6

50

I wanted to know if the {save} method in CrudRepository do an update if it finds already the entry in the database like :

@Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}

@Service
public class ProjectServiceImpl {

@Autowired private ProjectDAO pDAO;

public void save(Project p) { pDAO.save(p); } }

So if I call that method on an already registred entry, it'll update it if it finds a changed attribute ?

Thanks.

Louisville answered 11/8, 2016 at 10:31 Comment(0)
F
52

I wanted to know if the {save} method in CrudRepository do an update if it finds already the entry in the database

The Spring documentation about it is not precise :

Saves a given entity. Use the returned instance for further operations as the save operation might have changed the entity instance completely.

But as the CrudRepository interface doesn't propose another method with an explicit naming for updating an entity, we may suppose that yes since CRUD is expected to do all CRUD operations (CREATE, READ, UPDATE, DELETE).

This supposition is confirmed by the implementation of the SimpleJpaRepository class which is the default implementation of CrudRepository which shows that both cases are handled by the method :

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

So if I call that method on an already registered entry, it'll update it if it finds a changed attribute?

It will do a merge operation in this case. So all fields are updated according to how the merging cascade and read-only option are set.

Fadeless answered 11/8, 2016 at 11:0 Comment(5)
So if like the entity has a complex type, let's say an image, I think then I need to update with bare hands.Louisville
What do you mean by image ? If it is not a jpa relation field, it will be updated in any case indeed. So if the field is null in the entity to save , it will overwrite its value to null in the existing row.Fadeless
got it. another thing, here I see '@Transactionel' so I don't need to add that annotation to the service class no ?Louisville
@Transactional uses by default the propagration : Propagation.REQUIRED, which supports a current transaction, creating a new one if none exists. So, yes, it is not necessary to use @Transactional in your service but if you want to handle the rollback manually from the service method. If I addressed your question don't hesitate to accept it.Fadeless
I'm trying to use it on Spring boot 2.5.2 and it is not working, it is ignoring the ID of the entity and assigning a new one, thus creating a completely new entity (row).Utopia
S
26

Looking at the default implemantation of CrudRepository interface

 /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
     */
    @Transactional
    public <S extends T> S save(S entity) {

        if (entityInformation.isNew(entity)) {
            em.persist(entity);
            return entity;
        } else {
            return em.merge(entity);
        }
    }

Save method manage two situations:

-If the person Id is null (a new entity is created) then save will call persist method => insert query will be executed.

-If the person id is not null then save will call merge: fetch the existing entity from entityManagerFactory(from the 2 level cache if it doesn't exist then it will be fetched from the database) and comparing the detached entity with the managed and finally propagate the changes to the database by calling update query.

Spiritualism answered 11/8, 2016 at 11:0 Comment(0)
V
5

To be precise, the save(obj) method will treat obj as a new record if the id is empty (therefore will do an insert) and will treat obj as an existing record if the id is filled in (therefore will do the merge).

Why is this important?

Let's say the Project object contains an auto-generated id and also a person_id which must be unique. You make a Project object and fill in the person_id but not the id and then try to save. Hibernate will try to insert this record, since the id is empty, but if that person exists in the database already, you will get a duplicate key exception.

How to handle
Either do a findByPersonId(id) to check if the obj is in the db already, and get the id from that if it is found,
Or just try the save and catch the exception in which case you know it's in the db already and you need to get and set the id before saving.

Vortical answered 6/3, 2018 at 17:33 Comment(0)
H
2

I wanted to know if the {save} method in CrudRepository do an update if it finds already the entry in the database:

The Answer is Yes, It will update if it finds an entry:

From Spring Documentation: Herehttps://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html?

Saving an entity can be performed via the CrudRepository.save(…)-Method. It will persist or merge the given entity using the underlying JPA EntityManager. If the entity has not been persisted yet Spring Data JPA will save the entity via a call to the entityManager.persist(…)-Method, otherwise the entityManager.merge(…)-Method will be called.

Horseradish answered 2/11, 2017 at 19:0 Comment(0)
K
0

In my case I had to add the id property to the Entity, and put the annotation @Id like this.

@Id
private String id;

This way when you get the object has the Id of the entity in the database, and does the Update operation instead of the Create.

Knossos answered 2/5, 2018 at 15:17 Comment(0)
P
0

I suspect that - if the saving entity contains a valid primary key value, crudrepository.save() tries to update it, ow, it creates a new one and assign next available key from the system. That's why sometimes we get update error(500) when we tried to save a new record.

Princess answered 27/7, 2023 at 0:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.