How to beautifully update a JPA entity in Spring Data?

Lukas Makor picture Lukas Makor · Sep 28, 2016 · Viewed 150k times · Source

So I have looked at various tutorials about JPA with Spring Data and this has been done different on many occasions and I am no quite sure what the correct approach is.

Assume there is the follwing entity:

package stackoverflowTest.dao;

import javax.persistence.*;

@Entity
@Table(name = "customers")
public class Customer {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;

@Column(name = "name")
private String name;

public Customer(String name) {
    this.name = name;
}

public Customer() {
}

public long getId() {
    return id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

We also have a DTO which is retrieved in the service layer and then handed to the controller/client side.

package stackoverflowTest.dto;

public class CustomerDto {

private long id;
private String name;

public CustomerDto(long id, String name) {
    this.id = id;
    this.name = name;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

So now assume the Customer wants to change his name in the webui - then there will be some controller action, where there will be the updated DTO with the old ID and the new name.

Now I have to save this updated DTO to the database.

Unluckily currently there is no way to update an existing customer (except than deleting the entry in the DB and creating a new Cusomter with a new auto-generated id)

However as this is not feasible (especially considering such an entity could have hundreds of relations potentially) - so there come 2 straight forward solutions to my mind:

  1. make a setter for the id in the Customer class - and thus allow setting of the id and then save the Customer object via the corresponding repository.

or

  1. add the id field to the constructor and whenever you want to update a customer you always create a new object with the old id, but the new values for the other fields (in this case only the name)

So my question is wether there is a general rule how to do this? Any maybe what the drawbacks of the 2 methods I explained are?

Answer

Robert Niestroj picture Robert Niestroj · Sep 28, 2016

Even better then @Tanjim Rahman answer you can using Spring Data JPA use the method T getOne(ID id)

Customer customerToUpdate = customerRepository.getOne(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);

Is's better because getOne(ID id) gets you only a reference (proxy) object and does not fetch it from the DB. On this reference you can set what you want and on save() it will do just an SQL UPDATE statement like you expect it. In comparsion when you call find() like in @Tanjim Rahmans answer spring data JPA will do an SQL SELECT to physically fetch the entity from the DB, which you dont need, when you are just updating.