Programing

spring-data-jpa를 사용하여 엔티티를 어떻게 업데이트합니까?

crosscheck 2020. 5. 27. 21:38
반응형

spring-data-jpa를 사용하여 엔티티를 어떻게 업데이트합니까?


문제는 거의 모든 것을 말합니다. JPARepository를 사용하여 엔티티를 어떻게 업데이트합니까?

JPARepository에는 실제로 저장 또는 작성 중인지 알려주지 않는 저장 메소드 있습니다. 예를 들어, 나는 세 개의 필드가 데이터베이스 사용자에게 간단한 개체를 삽입 : firstname, lastnameage:

 @Entity
 public class User {

  private String firstname;
  private String lastname;
  //Setters and getters for age omitted, but they are the same as with firstname and lastname.
  private int age;

  @Column
  public String getFirstname() {
    return firstname;
  }
  public void setFirstname(String firstname) {
    this.firstname = firstname;
  }

  @Column
  public String getLastname() {
    return lastname;
  }
  public void setLastname(String lastname) {
    this.lastname = lastname;
  }

  private long userId;

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public long getUserId(){
    return this.userId;
  }

  public void setUserId(long userId){
    this.userId = userId;
  }
}

그런 다음 간단히 호출 save()하면 데이터베이스에 실제로 삽입됩니다.

 User user1 = new User();
 user1.setFirstname("john"); user1.setLastname("dew");
 user1.setAge(16);

 userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);

여태까지는 그런대로 잘됐다. 이제이 사용자를 업데이트하고 싶습니다. 나이를 바꾸십시오. 이 목적을 위해 QueryDSL 또는 NamedQuery와 같은 쿼리를 사용할 수 있습니다. 그러나 spring-data-jpa와 JPARepository를 사용하고 싶다는 것을 고려할 때 삽입 대신 업데이트를 원한다고 어떻게 알 수 있습니까?

특히, 동일한 사용자 이름과 이름을 가진 사용자가 실제로 동일하고 기존 엔티티가 업데이트되어야한다고 spring-data-jpa에 알리려면 어떻게해야합니까? equals를 재정의해도이 문제는 해결되지 않았습니다.


엔터티의 ID는 기본 키로 정의됩니다. 이후 firstnamelastname기본 키의 일부하지, 당신은 치료에 JPA를 말할 수 없다 User같은과의 firstnames와 lastname서로 다른 경우 동일로의 userId들.

따라서 and User식별 된 정보 를 업데이트 하려면 쿼리 식별 한 다음 찾은 객체의 해당 필드를 변경해야합니다. 이러한 변경 사항은 트랜잭션이 끝날 때 데이터베이스에 자동으로 플러시되므로 변경 사항을 명시 적으로 저장하기 위해 아무 것도 할 필요가 없습니다.firstnamelastnameUser

편집하다:

Perhaps I should elaborate on overall semantics of JPA. There are two main approaches to design of persistence APIs:

  • insert/update approach. When you need to modify the database you should call methods of persistence API explicitly: you call insert to insert an object, or update to save new state of the object to the database.

  • Unit of Work approach. In this case you have a set of objects managed by persistence library. All changes you make to these objects will be flushed to the database automatically at the end of Unit of Work (i.e. at the end of the current transaction in typical case). When you need to insert new record to the database, you make the corresponding object managed. Managed objects are identified by their primary keys, so that if you make an object with predefined primary key managed, it will be associated with the database record of the same id, and state of this object will be propagated to that record automatically.

JPA follows the later approach. save() in Spring Data JPA is backed by merge() in plain JPA, therefore it makes your entity managed as described above. It means that calling save() on an object with predefined id will update the corresponding database record rather than insert a new one, and also explains why save() is not called create().


Since the answer by @axtavt focuses on JPA not spring-data-jpa

To update an entity by querying then saving is not efficient because it requires two queries and possibly the query can be quite expensive since it may join other tables and load any collections that have fetchType=FetchType.EAGER

Spring-data-jpa supports update operation.
You have to define the method in Repository interface.and annotated it with @Query and @Modifying.

@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);

@Query is for defining custom query and @Modifying is for telling spring-data-jpa that this query is an update operation and it requires executeUpdate() not executeQuery().


You can simply use this function with save() JPAfunction, but the object sent as parameter must contain an existing id in the database otherwise it will not work, because save() when we send an object without id, it adds directly a row in database, but if we send an object with an existing id, it changes the columns already found in the database.

public void updateUser(Userinfos u) {
    User userFromDb = userRepository.findById(u.getid());
    // crush the variables of the object found
    userFromDb.setFirstname("john"); 
    userFromDb.setLastname("dew");
    userFromDb.setAge(16);
    userRepository.save(userFromDb);
}

As what has already mentioned by others, the save() itself contains both create and update operation.

I just want to add supplement about what behind the save() method.

Firstly, let's see the extend/implement hierarchy of the CrudRepository<T,ID>, enter image description here

Ok, let's check the save() implementation at SimpleJpaRepository<T, ID>,

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

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

As you can see, it will check whether the ID is existed or not firstly, if the entity is already there, only update will happen by merge(entity) method and if else, a new record is inserted by persist(entity) method.


Using spring-data-jpa save(), I was having same problem as @DtechNet. I mean every save() was creating new object instead of update. To solve this I had to add version field to entity and related table.


This is how I solved the problem:

User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);

spring data save() method will help you to perform both: adding new item and updating an existed item.

Just call the save() and enjoy the life :))


public void updateLaserDataByHumanId(String replacement, String humanId) {
    List<LaserData> laserDataByHumanId = laserDataRepository.findByHumanId(humanId);
    laserDataByHumanId.stream()
            .map(en -> en.setHumanId(replacement))
            .collect(Collectors.toList())
            .forEach(en -> laserDataRepository.save(en));
}

Specifically how do I tell spring-data-jpa that users that have the same username and firstname are actually EQUAL and that it is supposed to update the entity. Overriding equals did not work.

For this particular purpose one can introduce a composite key like this:

CREATE TABLE IF NOT EXISTS `test`.`user` (
  `username` VARCHAR(45) NOT NULL,
  `firstname` VARCHAR(45) NOT NULL,
  `description` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`username`, `firstname`))

Mapping:

@Embeddable
public class UserKey implements Serializable {
    protected String username;
    protected String firstname;

    public UserKey() {}

    public UserKey(String username, String firstname) {
        this.username = username;
        this.firstname = firstname;
    }
    // equals, hashCode
}

Here is how to use it:

@Entity
public class UserEntity implements Serializable {
    @EmbeddedId
    private UserKey primaryKey;

    private String description;

    //...
}

JpaRepository would look like this:

public interface UserEntityRepository extends JpaRepository<UserEntity, UserKey>

Then, you could use the following idiom: accept DTO with user info, extract name and firstname and create UserKey, then create a UserEntity with this composite key and then invoke Spring Data save() which should sort everything out for you.

참고URL : https://stackoverflow.com/questions/11881479/how-do-i-update-an-entity-using-spring-data-jpa

반응형