由于某些原因,我无法删除属于多对多关系的对象。我得到以下错误:
Exception in thread "main" org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [edu.cs157b.hibernate.AppointmentRequest#11]
at org.hibernate.internal.SessionImpl.forceFlush(SessionImpl.java:1232)
以下是我的三个类,它们映射了多对多关系。从本质上讲,Doctor
具有许多Patients
到AppointmentRequest
&反之亦然以下是的分类
医生
package edu.cs157b.hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
@Entity
@Table(name="DOCTOR_INFO")
@NamedQueries (
{
@NamedQuery(name = "Doctor.getAll", query = "from Doctor"),
@NamedQuery(name = "Doctor.findByName", query = "from Doctor where name = :name")
}
)
public class Doctor implements Person {
private int id;
private String name;
private Specialty specialty;
private List<AppointmentRequest> appointmentRequests = new ArrayList<AppointmentRequest>();
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(unique=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
@JoinColumn(name="specialty_id")
public Specialty getSpecialty() {
return specialty;
}
public void setSpecialty(Specialty specialty) {
this.specialty = specialty;
}
@OneToMany(mappedBy="doctor", targetEntity = AppointmentRequest.class,
fetch=FetchType.EAGER, orphanRemoval=true, cascade= CascadeType.ALL)
public List<AppointmentRequest> getAppointmentRequests() {
return this.appointmentRequests;
}
public void setAppointmentRequests(List<AppointmentRequest> appointmentRequests) {
this.appointmentRequests = appointmentRequests;
}
@Transient
public List<Patient> getPatients() {
List<Patient> patients = new ArrayList<Patient>();
for(AppointmentRequest appointment:appointmentRequests) {
patients.add(appointment.getPatient());
}
return patients;
}
}
患者
package edu.cs157b.hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
@Entity
@Table(name="PATIENT_INFO")
@NamedQueries (
{
@NamedQuery(name = "Patient.getAll", query = "from Patient"),
@NamedQuery(name = "Patient.findByName", query = "from Patient where name = :name")
}
)
public class Patient implements Person {
private int id;
private String name;
private String medical_record;
private List<AppointmentRequest> appointmentRequests = new ArrayList<AppointmentRequest>();
public String getMedical_record() {
return medical_record;
}
public void setMedical_record(String medical_record) {
this.medical_record = medical_record;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(unique=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy="patient", targetEntity = AppointmentRequest.class,
fetch=FetchType.EAGER, orphanRemoval=true, cascade= CascadeType.ALL)
public List<AppointmentRequest> getAppointmentRequests() {
return this.appointmentRequests;
}
public void setAppointmentRequests(List<AppointmentRequest> appointmentRequests) {
this.appointmentRequests = appointmentRequests;
}
@Transient
public List<Doctor> getDoctors() {
List<Doctor> doctors = new ArrayList<Doctor>();
for(AppointmentRequest appointment:appointmentRequests) {
doctors.add(appointment.getDoctor());
}
return doctors;
}
}
应用程序请求
package edu.cs157b.hibernate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
import javax.persistence.*;
import org.hibernate.annotations.Type;
import java.util.List;
@Entity
@Table(name="APPOINTMENT_REQUEST")
@NamedQueries (
{
@NamedQuery(name = "AppointmentRequest.getAll", query = "from AppointmentRequest"),
@NamedQuery(name = "AppointmentRequest.findByDoctorId", query = "from AppointmentRequest where doctor_id = :doctor_id"),
@NamedQuery(name = "AppointmentRequest.findByPatientId", query = "from AppointmentRequest where patient_id = :patient_id"),
@NamedQuery(name = "AppointmentRequest.findByID", query = "from AppointmentRequest where id = :id")
}
)
public class AppointmentRequest {
private int id;
private Doctor doctor;
private Patient patient;
private boolean fulfilled = false;
private Calendar time;
private final SimpleDateFormat timestampFormat = new SimpleDateFormat("MM/dd/yyyy h a");
public Calendar getTime() {
return time;
}
@Transient
public String getFormattedTime() {
String result = timestampFormat.format(time.getTime());
return result;
}
public void setTime(Calendar time) {
this.time = time;
}
public boolean isFulfilled() {
return fulfilled;
}
public void setFulfilled(boolean fulfilled) {
this.fulfilled = fulfilled;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
@JoinColumn(name="doctor_id")
public Doctor getDoctor() {
return doctor;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
@ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
@JoinColumn(name="patient_id")
public Patient getPatient() {
return patient;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
}
医生删除方法
public void deleteDoctor(String doctor_name) {
Session session = sessionFactory.openSession();
Doctor doctor = new Doctor();
try {
session.beginTransaction();
Query query = session.getNamedQuery("Doctor.findByName");
query.setString("name", doctor_name);
doctor = (Doctor) query.uniqueResult();
if(doctor == null) {
throw new NullPointerException();
}
List<AppointmentRequest> appointments = doctor.getAppointmentRequests();
for(AppointmentRequest appointment:appointments) {
appointment.setDoctor(null);
}
session.delete(doctor);
session.getTransaction().commit();
}
finally {
session.close();
}
}
这个异常的真正含义是,你告诉Hibernate从数据库中删除对象,但同时这个对象仍然存在(这意味着仍然存在于java或数据库中),通过带有CascadeType.PERSIST
注释的Persistent实体在映射的集合中。
这就像有东西通过弹性橡胶绑在窗户上,然后戳它,希望它会掉下来。Hibernate很聪明,它可以让你免于做无意义的事情,它告诉你该做什么
删除的对象将被重新保存通过级联(从关联中删除已删除的对象)
在执行appointment.setDoctor(null);
时,它将从集合中删除对象(仅在java中,因为您没有显式或隐式更新appointment
)。您在doctor
上有CascadeType.PERSIST
,这意味着当hibernate要提交事务时,它会发现appointment
与您刚刚删除的doctor
有关联从表中删除doctor
,hibernate必须去创建相同的doctor
因为您没有告诉他在appointment
中进行适当的更改,因为他遵循您设置的所有实体规则。既然hibernate很聪明,他知道这一点,他会为你破例说不要做矛盾修辞法,做正确的事。
现在有不止一个解决方案,我可以想到这里
-
在
AppointmentRequest
中的getDoctor()
上使用cascade={CascadeType.PERSIST,CascadeType.REMOVE}
或cascade=CascadeType.ALL
-
如hibernate文档中所述
在@ManyToOne或@ManyToMany协会。Cascade通常对@OneToOne和@一对多关联。
从
getDoctor
中删除级联 -
由于您在指定了
cascade
的getDoctor()
上有FetchType.EAGER
,所以我解释hibernate的行为有点复杂,但在他们使用FetchType.LAZY
解决的这个问题中,我不确定它是否适用于您。 -
你可以在所有有这个医生的
AppointmentRequest
上做session.saveOrUpdate(appointment)
,然后进行session.delete(doctor);
希望这能解决你的问题。