복붙노트

[SPRING] JPA : 특정 필드 만 업데이트

SPRING

JPA : 특정 필드 만 업데이트

Spring Data JPA에서 save 메소드를 사용하여 엔티티 객체의 일부 필드 만 업데이트하는 방법이 있습니까?

예를 들어 다음과 같은 JPA 엔티티가 있습니다.

@Entity
public class User {

  @Id
  private Long id;

  @NotNull
  private String login;

  @Id
  private String name;

  // getter / setter
  // ...
}

그것의 CRUD repo로 :

public interface UserRepository extends CrudRepository<User, Long> { }

스프링 MVC에서 나는 그것을 업데이트하기 위해 User 객체를 얻는 컨트롤러를 가지고있다 :

@RequestMapping(value = "/rest/user", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> updateUser(@RequestBody User user) {

   // Assuming that user have its id and it is already stored in the database,
   // and user.login is null since I don't want to change it,
   // while user.name have the new value

   // I would update only its name while the login value should keep the value 
   // in the database
   userRepository.save(user);

   // ...
}

findOne을 사용하여 사용자를로드 한 다음 이름을 변경하고 save를 사용하여 업데이트 할 수 있음을 알고 있습니다. 그러나 100 개의 필드가 있고 그 중 50 개를 업데이트하려는 경우 각 값을 변경하는 것이 매우 귀찮습니다.

"개체를 저장할 때 모든 null 값을 건너 뛰기"와 같은 것을 말할 수있는 방법이 있습니까?

해결법

  1. ==============================

    1.나는 같은 질문을했고 M. Deinum이 지적한 것처럼 대답은 아니오, 당신은 save를 사용할 수 없다. 가장 큰 문제점은 스프링 데이터가 null을 어떻게 처리해야하는지 알지 못한다는 것입니다. null 값이 설정되어 있지 않거나 삭제해야하기 때문에 설정되어 있습니까?

    나는 같은 질문을했고 M. Deinum이 지적한 것처럼 대답은 아니오, 당신은 save를 사용할 수 없다. 가장 큰 문제점은 스프링 데이터가 null을 어떻게 처리해야하는지 알지 못한다는 것입니다. null 값이 설정되어 있지 않거나 삭제해야하기 때문에 설정되어 있습니까?

    이제 당신의 질문에 비추어 볼 때, 내가 가진 생각과 똑같은 생각을했다고 가정합니다. 그것은 저축으로 인해 모든 변경된 값을 수동으로 설정하지 않아도된다는 것입니다.

    그래서 모든 마누엘 매핑을 피하는 것이 가능합니까? 글쎄, 당신이 nulls가 항상 '설정되지 않음'을 의미하고 원래의 모델 ID를 가지고 있다는 것을 대회에 충실하게한다면, 그렇다. Springs BeanUtils를 사용하여 맵핑을 피할 수 있습니다.

    당신은 다음을 할 수 있습니다 :

    이제 Spring의 BeanUtils는 null 값을 복사하지 않는 것을 지원하지 않으므로 기존 모델 객체에서 null로 설정되지 않은 모든 값을 덮어 씁니다. 다행히도 여기에 해결책이 있습니다.

    springframework BeanUtils copyProperties를 사용하여 null 값을 무시하는 방법?

    그래서이 모든 것을 합치면 결국 이런 식으로 끝날 것입니다.

    @RequestMapping(value = "/rest/user", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<?> updateUser(@RequestBody User user) {
    
       User existing = userRepository.read(user.getId());
       copyNonNullProperties(user, existing);
       userRepository.save(existing);
    
       // ...
    }
    
    public static void copyNonNullProperties(Object src, Object target) {
        BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }
    
    public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
    
        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }
    
  2. ==============================

    2.JPA를 사용하면 이렇게 할 수 있습니다.

    JPA를 사용하면 이렇게 할 수 있습니다.

    CriteriaBuilder builder = session.getCriteriaBuilder();
    CriteriaUpdate<User> criteria = builder.createCriteriaUpdate(User.class);
    Root<User> root = criteria.from(User.class);
    criteria.set(root.get("lastSeen"), date);
    criteria.where(builder.equal(root.get("id"), user.getId()));
    session.createQuery(criteria).executeUpdate();
    
  3. ==============================

    3.문제는 스프링 데이터 jpa 관련이 아니라 jpa 구현 lib 당신이 관련을 사용하고 있습니다. 최대 절전 모드의 경우 다음을 살펴보십시오.

    문제는 스프링 데이터 jpa 관련이 아니라 jpa 구현 lib 당신이 관련을 사용하고 있습니다. 최대 절전 모드의 경우 다음을 살펴보십시오.

    http://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/

  4. ==============================

    4.요청을 JSON String으로 읽는 중이라면 Jackson API를 사용하여 요청을 처리 할 수 ​​있습니다. 여기에 코드가 있습니다. 코드는 기존 POJO 요소를 비교하고 업데이트 된 필드로 새 요소를 만듭니다. 새로운 POJO를 사용하여 지속하십시오.

    요청을 JSON String으로 읽는 중이라면 Jackson API를 사용하여 요청을 처리 할 수 ​​있습니다. 여기에 코드가 있습니다. 코드는 기존 POJO 요소를 비교하고 업데이트 된 필드로 새 요소를 만듭니다. 새로운 POJO를 사용하여 지속하십시오.

    public class TestJacksonUpdate {
    
    class Person implements Serializable {
        private static final long serialVersionUID = -7207591780123645266L;
        public String code = "1000";
        public String firstNm = "John";
        public String lastNm;
        public Integer age;
        public String comments = "Old Comments";
    
        @Override
        public String toString() {
            return "Person [code=" + code + ", firstNm=" + firstNm + ", lastNm=" + lastNm + ", age=" + age
                    + ", comments=" + comments + "]";
        }
    }
    
    public static void main(String[] args) throws JsonProcessingException, IOException {
        TestJacksonUpdate o = new TestJacksonUpdate();
    
        String input = "{\"code\":\"1000\",\"lastNm\":\"Smith\",\"comments\":\"Jackson Update WOW\"}";
        Person persist = o.new Person();
    
        System.out.println("persist: " + persist);
    
        ObjectMapper mapper = new ObjectMapper();
        Person finalPerson = mapper.readerForUpdating(persist).readValue(input);
    
        System.out.println("Final: " + finalPerson);
    }}
    

    마지막 출력은 lastNm 및 Notice 만 변경 사항을 반영한다는 것입니다.

    persist: Person [code=1000, firstNm=John, lastNm=null, age=null, comments=Old Comments]
    Final: Person [code=1000, firstNm=John, lastNm=Smith, age=null, comments=Jackson Update WOW]
    
  5. ==============================

    5.당신은 다음과 같은 것을 쓸 수 있습니다.

    당신은 다음과 같은 것을 쓸 수 있습니다.

    @Modifying
        @Query("update StudentXGroup iSxG set iSxG.deleteStatute = 1 where iSxG.groupId = ?1")
        Integer deleteStudnetsFromDeltedGroup(Integer groupId);
    

    또는 수정 된 필드 만 업데이트하려면 주석을 사용할 수 있습니다

    @DynamicUpdate
    

    코드 예 :

    @Entity
    @Table(name = "lesson", schema = "oma")
    @Where(clause = "delete_statute = 0")
    @DynamicUpdate
    @SQLDelete(sql = "update oma.lesson set delete_statute = 1, "
            + "delete_date = CURRENT_TIMESTAMP, "
            + "delete_user = '@currentUser' "
            + "where lesson_id = ?")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    
  6. ==============================

    6.long, int 및 다른 유형; 다음 코드를 사용할 수 있습니다.

    long, int 및 다른 유형; 다음 코드를 사용할 수 있습니다.

                if (srcValue == null|(src.getPropertyTypeDescriptor(pd.getName()).getType().equals(long.class) && srcValue.toString().equals("0")))
                emptyNames.add(pd.getName());
    
  7. from https://stackoverflow.com/questions/27818334/jpa-update-only-specific-fields by cc-by-sa and MIT license