使用关联

时间:2017-09-28 08:07:47

标签: java hibernate jpa

上下文

我有一个同时具有@OneToMany@ManyToMany关联的实体。我从前端收到一个对象,其中只设置了一些属性(不是关联)。目标是更新数据库中该实体的数据。

问题

接收的对象是一个分离的实体,因此在更新时,将调用合并操作。由于未设置关联,@ManyToMany部分将被删除,但不会删除@OneToMany(因为没有级联)。一种选择是从加载了@ManyToMany关联的数据库中检索实体,然后将所有属性从前端对象复制到该实体然后合并,保留对象,但我不确定这是最佳实践。 / p>

代码

在数据库中创建完整对象

    Course hibernate = new Course();
    hibernate.setName("Hibernate");
    Course java = new Course();
    java.setName("Java");
    entityManager.persist(hibernate);
    entityManager.persist(java);
    Address address = new Address();
    address.setName("White House");
    entityManager.persist(address);
    Student student = new Student();
    student.setName("Sydney");
    student.addAddress(address);
    student.addCourse(hibernate);
    student.addCourse(java);
    entityManager.persistAndFlush(student);
    entityManager.clear();

    Hibernate: call next value for hibernate_sequence
    Hibernate: call next value for hibernate_sequence
    Hibernate: call next value for hibernate_sequence
    Hibernate: call next value for hibernate_sequence
    Hibernate: insert into course (name, id) values (?, ?)
    Hibernate: insert into course (name, id) values (?, ?)
    Hibernate: insert into address (name, student_id, id) values (?, ?, ?)
    Hibernate: insert into student (name, id) values (?, ?)
    Hibernate: update address set name=?, student_id=? where id=?
    Hibernate: insert into student_course (students_id, courses_id) values (?, ?)
    Hibernate: insert into student_course (students_id, courses_id) values (?, ?)

坚持前端的对象

    Student partialStudent = new Student();
    partialStudent.setId(student.getId());
    partialStudent.setName("Sydney Updated");
    Student attachedPartialStudent = entityManager.merge(partialStudent);
    entityManager.persistAndFlush(attachedPartialStudent);
    entityManager.clear();

此部分生成DELETE SQL

    Hibernate: select student0_.id as id1_41_0_, student0_.name as name2_41_0_ from student student0_ where student0_.id=?
    Hibernate: select courses0_.students_id as students1_42_0_, courses0_.courses_id as courses_2_42_0_, course1_.id as id1_13_1_, course1_.name as name2_13_1_ from student_course courses0_ inner join course course1_ on courses0_.courses_id=course1_.id where courses0_.students_id=?
    Hibernate: update student set name=? where id=?
    Hibernate: delete from student_course where students_id=?

学生实体:

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @NotNull
    @Column(name = "name", nullable = false)
    private String name;

    @OneToMany(mappedBy = "student")
    private Set<Address> addresses = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "student_course")
    private Set<Course> courses = new HashSet<>();

    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 Set<Course> getCourses() {
        return courses;
    }

    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }

    public void addCourse(Course course) {
        courses.add(course);
        course.getStudents().add(this);
    }

    public void removeCourse(Course course) {
        courses.remove(course);
        course.getStudents().remove(this);
    }

    public Set<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(Set<Address> addresses) {
        this.addresses = addresses;
    }

    public void addAddress(Address address) {
        addresses.add(address);
        address.setStudent(this);
    }

    public void removeAddress(Address address) {
        addresses.remove(address);
        address.setStudent(null);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

课程实体:

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @NotNull
    @Column(name = "name", nullable = false)
    private String name;

    @ManyToMany(mappedBy = "courses")
    private Set<Student> students = new HashSet<>();

    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 Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }

    public void addStudent(Student student) {
        students.add(student);
        student.getCourses().add(this);
    }

    public void removeStudent(Student student) {
        students.remove(student);
        student.getCourses().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Course)) return false;
        Course course = (Course) o;
        return Objects.equals(id, course.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

地址实体:

@Entity
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @NotNull
    @Column(name = "name", nullable = false)
    private String name;

    @ManyToOne
    private Student student;

    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 Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Address)) return false;
        Address address = (Address) o;
        return Objects.equals(id, address.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

1 个答案:

答案 0 :(得分:0)

  

接收的对象是一个分离的实体,因此在更新时,将调用合并操作。由于未设置关联, @ManyToMany部分将被删除,但不会删除@OneToMany(因为没有级联)。

由于您有一个分离的实体,正常的用例是您将其传递给前端,在前端对实体进行了一些更改。当此修改后的实体实例从前端返回并且您调用entitymanager.merge()操作时,它不应该从数据库中删除关联。

您正在描述的情况,即关联被删除(无论是否设置了级联)只有在您将关联设置为null

时才会发生
student.setCourses(null);

或者如果您创建了Student的新实例,比如studentNew,则复制原始分离实例的某些字段,并将studentNew传递给fronend。在这种情况下,从前端收到coursesnull属性为studentNew。如果发生这种情况,您有两种选择:

  • 如果您有旧的分离实例,请将studentNew的状态复制回来并合并该实例。

  • 否则,您必须使用ID从数据库加载实体,并将更改后的状态复制到托管实例。