上下文
我有一个同时具有@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);
}
}
答案 0 :(得分:0)
接收的对象是一个分离的实体,因此在更新时,将调用合并操作。由于未设置关联, @ManyToMany部分将被删除,但不会删除@OneToMany(因为没有级联)。
由于您有一个分离的实体,正常的用例是您将其传递给前端,在前端对实体进行了一些更改。当此修改后的实体实例从前端返回并且您调用entitymanager.merge()
操作时,它不应该从数据库中删除关联。
您正在描述的情况,即关联被删除(无论是否设置了级联)只有在您将关联设置为null
student.setCourses(null);
或者如果您创建了Student
的新实例,比如studentNew
,则复制原始分离实例的某些字段,并将studentNew
传递给fronend。在这种情况下,从前端收到courses
时null
属性为studentNew
。如果发生这种情况,您有两种选择:
如果您有旧的分离实例,请将studentNew
的状态复制回来并合并该实例。
否则,您必须使用ID从数据库加载实体,并将更改后的状态复制到托管实例。