JPA: 특정 필드만 업데이트
메서드를 사용하여 엔티티 객체의 일부 필드만 업데이트하는 방법이 있습니까?save
Spring Data JPA에서요?
예를 들어 다음과 같은 JPA 엔티티가 있습니다.
@Entity
public class User {
@Id
private Long id;
@NotNull
private String login;
@Id
private String name;
// getter / setter
// ...
}
CRUD 보고서 사용 시:
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 값을 건너뜁니다"와 같은 것을 알 수 있는 방법은 없습니까?
저도 M과 같은 질문이 있었어요.Deinum이 지적합니다. 정답은 "아니오"입니다. "저장"은 사용할 수 없습니다.가장 큰 문제는 스프링 데이터가 늘을 어떻게 처리해야 할지 모른다는 것입니다.null 값이 설정되지 않았습니까, 아니면 삭제가 필요하기 때문에 설정되었습니까?
질문하신 내용으로 판단하건대, 저와 같은 생각을 하고 계신 것 같습니다.즉, 저장하면 변경된 값을 수동으로 설정하지 않아도 됩니다.
그럼 모든 Manuel 매핑을 피할 수 있을까요?Null은 항상 '설정되지 않음'을 의미하고 원래 모델 ID를 가지고 있다는 관례를 따르기로 선택했다면, 그렇습니다.Springs Bean Utils를 사용하면 매핑을 피할 수 있습니다.
다음 작업을 수행할 수 있습니다.
- 기존 객체 읽기
- 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);
}
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();
다음과 같은 것을 쓸 수 있습니다.
@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"})
요청을 JSON String으로 읽는 경우 Jackson API를 사용하여 요청을 읽을 수 있습니다.아래 코드는 다음과 같습니다.코드는 기존 POJO 요소를 비교하고 업데이트된 필드와 새 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);
}}
최종 출력은 Notice only lastNm 및 Comments 에는 변경이 반영되어 있습니다.
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]
개체를 저장할 때 모든 null 값을 건너뜁니다.
다른 사람들이 지적했듯이 JPA에는 직접적인 해결책이 없다.
하지만 처음부터 MapStruct를 사용할 수 있습니다.
, 의 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,find()
메서드를 사용하여 DB에서 개체를 업데이트하고 null이 아닌 속성만 덮어쓴 다음 개체를 저장합니다.
JPA를 사용하면 Spring에서 다음과 같이 MapStruct를 사용하여 DB에서 개체의 null이 아닌 속성만 업데이트할 수 있습니다.
@Mapper(componentModel = "spring")
public interface HolidayDTOMapper {
/**
* Null values in the fields of the DTO will not be set as null in the target. They will be ignored instead.
*
* @return The target Holiday object
*/
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
Holiday updateWithNullAsNoChange(HolidayDTO holidayDTO, @MappingTarget Holiday holiday);
}
자세한 내용은 MapStruct 문서를 참조하십시오.
할 수 있어요.HolidayDTOMapper
콩과 @Autowired
...) Lombok, ...)
문제는 스프링 데이터 jpa가 아니라 사용 중인 jpa 구현 lib와 관련된 것입니다.휴지 상태일 경우 다음을 볼 수 있습니다.
http://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/
long, int 및 기타 유형의 경우 다음 코드를 사용할 수 있습니다.
if (srcValue == null|(src.getPropertyTypeDescriptor(pd.getName()).getType().equals(long.class) && srcValue.toString().equals("0")))
emptyNames.add(pd.getName());
언급URL : https://stackoverflow.com/questions/27818334/jpa-update-only-specific-fields
'programing' 카테고리의 다른 글
응용 프로그램 설정 파일 (0) | 2023.03.20 |
---|---|
Next.js에서의 인증 구현 방법 (0) | 2023.03.20 |
컴포넌트 상태를 직접 변경할 수 없는 이유는 무엇입니까? (0) | 2023.03.20 |
각도 JS: IE 오류: 10 $digest() 반복에 도달했습니다.중단 중 (0) | 2023.03.20 |
JSON 구문 분석 오류: io.starter.topic 인스턴스를 생성할 수 없습니다.주제 (0) | 2023.03.20 |