如何使用JPA存储库更新实体中的一个字段

时间:2019-01-30 16:09:34

标签: java spring spring-data-jpa

我有3个字段的实体:id,姓氏和phoneNumber。我想创建一种适用于更新所有字段或仅更新一两个字段的方法。

我使用Hibernate和JPA存储库。 当我尝试更新所有字段时,一切正常,但是例如,当我只想更新姓氏而不更改phoneNumber时,我在输出null时会插入旧的phoneNumber。

这是我来自Controller的方法:

@PutMapping("/students/update/{id}")
public String updateStudentById(@ModelAttribute Student student, @ModelAttribute StudentDetails studentDetails,
                                String lastname, String phoneNumber,
                                @PathVariable Long id) {

    Optional<Student> resultOptional = studentRepository.findById(id); 

    //Student result =resultOptional.get();
    resultOptional.ifPresent((Student result) -> {
           result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber());     result.getStudentDetails().setLastname(studentDetails.getLastname());
        studentRepository.save(result);
    });
    return "Student updated";
}

要更新的类:

@DynamicUpdate
@Entity
public class StudentDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name="lastname")
    private String lastname;
    @Column(name="phone_number")
    private String phoneNumber;

    public StudentDetails() {
    }

    public StudentDetails(Long id, String lastname, String phoneNumber) {
        this.id = id;
        this.lastname = lastname;
        this.phoneNumber = phoneNumber;
    }

    public Long getId() {
        return id;
    }

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

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}

与StudentDetails相关的类:

@Entity
@Table(name = "student")
@DynamicUpdate
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

    //@OneToMany(mappedBy = "student")
    @ManyToMany
    @JoinTable(name="course_student",joinColumns = @JoinColumn(name="student_id"),
    inverseJoinColumns = @JoinColumn(name="course_id"))

    private List<Courses> courses;

    @OneToOne(cascade = CascadeType.ALL)
   // @JoinColumn(name="studen/_details_id") // with this we have dobule student_details column
    private  StudentDetails studentDetails;


    public List<Courses> getCourses() {
        return courses;
    }

    public void setCourses(List<Courses> courses) {
        this.courses = courses;
    }

    public StudentDetails getStudentDetails() {
        return studentDetails;
    }

    public void setStudentDetails(StudentDetails studentDetails) {
        this.studentDetails = studentDetails;
    }

    // Methods for StudentViewController
    public String getLastname(){
        return studentDetails.getLastname();
    }
    public String getPhoneNumber(){
        return studentDetails.getPhoneNumber();
    }

    public Student() {
    }

    public Student(String name, String email, StudentDetails studentDetails) {
       // this.id = id;
        this.name = name;
        this.email = email;
        this.studentDetails = studentDetails;
    }

    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;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }

}

我正在寻找解决方案,我添加了@DynamicUpdate,但仍然无法正常工作。

3 个答案:

答案 0 :(得分:0)

为什么不只是在设置器中设置请求的参数?

resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(phoneNumber);
result.getStudentDetails().setLastname(lastname);
studentRepository.save(result);
});

答案 1 :(得分:0)

您忘记了StudentDetails中设置的@OneToOne映射-StudentDetails还需要类型为Student的字段,该字段将被注释为@OneToOne。

还必须确保所有实体字段都将被填充-了解有关提取类型的更多信息。

答案 2 :(得分:0)

您的代码正常工作。当您仅在请求中提供lastName参数时,phoneNumber参数将映射到null,因此您可以使用此{{1}覆盖实体中的phoneNumer属性}值。

通过以下方式更改代码:

null

不幸的是,这引起了另一个问题:如何删除这些字段? (如何将它们显式设置为resultOptional.ifPresent((Student result) -> { if(studentDetails.getPhoneNumber()!=null) { result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber()); } if(studentDetails.getLastname()!=null) { result.getStudentDetails().setLastname(studentDetails.getLastname()); } studentRepository.save(result); }); ?)

如果您检查null(空字符串)并将属性设置为""(如果参数为空字符串),则可能是一种解决方案。

反正这将是一个非常混乱的代码...

您应该考虑使用Spring Data Rest软件包。它会自动为您的实体创建所有标准REST端点,并开箱即用地处理所有这些PUT / PATCH / POST / DELETE问题。