복붙노트

[SPRING] JPA에서 Spring MVC를 사용하여 엔티티의 속성 하위 집합 만 업데이트 할 수 있습니까?

SPRING

JPA에서 Spring MVC를 사용하여 엔티티의 속성 하위 집합 만 업데이트 할 수 있습니까?

Spring Roo에서 Spring MVC와 JPA를 사용하여 MySQL 데이터베이스에서 지속성을 유지하려고합니다. 저는 Spring MVC와 Java에 대해 매우 익숙하지만 CakePHP와 Rails를 사용해 왔습니다.

암호와 함께 개인 정보가 포함 된 User 엔티티가 있습니다. 다음과 같은 것 (추가 .aj 파일에서 Roo가 생성 한 많은 기능 제외) :

public class User {

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

    @Column(name = "PASSWORD", length = 32)
    private String password;

    @Column(name = "FIRST_NAME", length = 25)
    private String firstName;

    @Column(name = "LAST_NAME", length = 25)
    private String lastName;

    @Column(name = "ADDRESS", length = 255)
    private String address;

    // The appropriate getters and setters
    ...
}

그런 다음 사용자 컨트롤러에서 Roo의 자동 생성 스 캐 폴딩 규칙에 따라 만든 편집 동작이 있습니다.

@RequestMapping(value="/edit", method = RequestMethod.GET)
public String editForm(Model uiModel) {
    String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    uiModel.addAttribute("user", User.findUserByUsername(username).getSingleResult());
    return "account/edit";
}

그리고 Roo의 규칙을 다시 따르는 JSPX 뷰는 폼을 렌더링한다.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <form:update id="" label="Personal Details" modelAttribute="user" path="/account" versionField="none">
        <field:input id="" field="firstName" label="First Name" />
        <field:input id="" field="lastName" label="Last Name" />
        <field:textarea id="" field="address" label="Street Address" />
    </form:update>
</div>

양식에서 암호, 단지 제공된 필드 (이름, 성 및 주소) 만 업데이트하도록하지는 않습니다.

Roo 관례에 따라 업데이트 작업 :

@RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String edit(@Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
    if (bindingResult.hasErrors()) {
        uiModel.addAttribute("user", user);
        return "account/edit";
    }
    uiModel.asMap().clear();
    user.merge();
    return "redirect:/account";
}

사용자 객체는 완벽하게 업데이트되지만 양식의 입력으로 제공되지 않아 양식 제출 요청 처리기로 전달 된 User 객체에서 null로 설정되므로 암호 필드를 null로 덮어 쓰는 것이 문제입니다. Roo가 생성 한 스캐 폴딩에서는 모든 열에 대해 양식 입력을 제공하기 때문에 문제가 나타나지 않습니다. 그래서 그것을 숨겨진 필드로 추가 할 수는 있지만 좋은 생각처럼 들리지는 않습니다. 그리고 나는 그것을하는 훨씬 더 좋은 방법이 있다는 느낌을 얻습니다 ...

다시 말해, Spring / JPA가 SQL을 생성하게하는 방법은 무엇입니까?

UPDATE user SET firstname=?, lastname=?, address=?

대신에

UPDATE user SET firstname=?, lastname=?, address=?, password=?

내가이 모든 것을 처음 접했기 때문에 코드 샘플이 환상적 일 것입니다. :)

고맙습니다!

업데이트 : 나는 그것을 사용자 모델에 다음 메소드를 추가하여 yglodt의 제안을 사용하여 작동하게 만들 수있었습니다.

@Transactional
public void mergeWithExistingAndUpdate() {
    final User existingUser = User.findUser(this.getId());

    existingUser.setFirstName(this.getFirstName());
    existingUser.setLastName(this.getLastName());
    existingUser.setAddress(this.getAddress());

    existingUser.flush();
}

user.merge () 대신 내 컨트롤러 액션에서 호출 :

user.mergeWithExistingAndUpdate();

해결법

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

    1.나는 보통 이것을 서비스 계층에서 해결한다.

    나는 보통 이것을 서비스 계층에서 해결한다.

    DB에서 갱신하려는 엔티티를 읽고 양식에서 가져 오는 속성을 겹쳐 쓸 수 있습니다.

    이렇게하면 원하는 속성 만 변경할 수 있습니다.

    코드 예 :

    @Service
    @Transactional
    public class UserService {
    
        @Resource(name = "sessionFactory")
        private SessionFactory  sessionFactory;
    
        public void mergeWithExistingAndUpdate(final Person personFromPost) {
    
            Session session = sessionFactory.getCurrentSession();
    
            Person existingPerson = (Person) session.get(Person.class, personFromPost.getId());
    
            // set here explicitly what must/can be overwritten by the html form POST
            existingPerson.setName(personFromPost.getName());
            existingPerson.setEmail(personFromPost.getEmail());
            existingPerson.setDateModified(new Date());
            existingPerson.setUserModified(Utils.getCurrentUser());
    
            session.update(existingPerson);
        }
    
    }
    

    1 편집

    실제로이 문제를 해결할 Spring 방식이 있습니다. @SessionAttributes를 사용하면이 anwer를 볼 수 있습니다.

    https://stackoverflow.com/a/3675919/272180

    아직 테스트하지는 않았지만 유망 해 보입니다.

    EDIT 2

    결국 나는 그것을 테스트하고 예상대로 작동합니다.

    그러나 발로 쏘을 수있는 한 가지가 있습니다.

    같은 양식으로 여러 탭을 열면 마지막 탭의 여는 부분은 다른 탭의 sessionAttribute를 덮어 쓰며 제출할 때 잠재적으로 데이터가 손상 될 수 있습니다. 이 블로그 게시물에 해결 방법이 있습니다. http://marty-java-dev.blogspot.com/2010/09/spring-3-session-level-model-attributes.html

    그러나 결국 편집을 위해 여러 개의 탭을 열지 않으면 어쨌든 문제가 발생하지 않습니다.

  2. ==============================

    2.이 기사에서는 귀하의 질문에 대해 자세히 설명하지만, 여기에서도 요약 해 보겠습니다.

    이 기사에서는 귀하의 질문에 대해 자세히 설명하지만, 여기에서도 요약 해 보겠습니다.

    특정 속성을 업데이트하지 않으려면 updatable = false로 표시 할 수 있습니다.

    @Column(name="CREATED_ON", updatable=false)
    private Date createdOn;
    

    현재 Session이나 EntityManager가 열려있는 한 엔티티를로드하고 수정하면 Hibernate는 더티 확인 메커니즘을 통해 변경 사항을 추적 할 수 있습니다. 그런 다음 플러시하는 동안 SQL 업데이트가 실행됩니다.

    모든 열이 UPDATE 문에 포함되는 것이 마음에 들지 않으면 동적 업데이트를 사용할 수 있습니다.

    @Entity
    @DynamicUpdate
    public class Product {
       //code omitted for brevity
    }
    

    그런 다음 수정 된 열만 UPDATE 문에 포함됩니다.

  3. ==============================

    3.퍼시스턴스 프로 바이더가 Hibernate 인 경우 엔티티에서 최대 절전 모드 별 주석을 사용하십시오 : @DynamicUpdate :

    퍼시스턴스 프로 바이더가 Hibernate 인 경우 엔티티에서 최대 절전 모드 별 주석을 사용하십시오 : @DynamicUpdate :

  4. from https://stackoverflow.com/questions/14699087/is-it-possible-to-update-only-a-subset-of-attributes-on-an-entity-using-spring-m by cc-by-sa and MIT license