Hibernate ManyToMany已删除的对象将被级联重新保存 [英] Hibernate ManyToMany deleted object would be re-saved by cascade

查看:191
本文介绍了Hibernate ManyToMany已删除的对象将被级联重新保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于某种原因,我无法删除属于多对多关系的对象。我收到以下错误:

For some reason I can't delete an object that belongs to a many to many relationship. I get the following error:

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)

这是我的三个类,映射了许多关系。基本上,医生有许多患者通过 AppointmentRequest &反之亦然。以下是课程

Here are my three classes that map the many to many relationship. Essentially, Doctor has many Patients through AppointmentRequest & vice versa. Here are the classes

医生

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

ApppointmentRequest

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

}

/ strong>

Doctor Delete Method

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 注释。

What this exception really means is you are telling Hibernate to remove object from database but at the same time this object still exist (that means still exist in java or database) in mapped collection via Persistent entity which has CascadeType.PERSIST annotated over it.

这就像在窗户上用弹性橡胶捆绑的东西,然后戳它希望它会下降。 Hibernate是很聪明的,它可以让你无意义的东西,它告诉你要做什么

It's like having something tied through elastic rubber on the window and then poke it hoping it will drop. Hibernate is smart it is saving you from doing meaningless stuff, it tells you what to do


删除的对象将被重新保存
通过级联( 从关联中删除已删除的对象

deleted object would be re-saved by cascade (remove deleted object from associations)

执行 dating.setDoctor(null); 它将从集合中删除对象(仅在java中,因为您没有显式或隐式更新 约会).你有 CascadeType.PERSIST 医生 这意味着当hibernate要提交交易时,它会发现 约会 已经关联到 医生 你刚刚删除,这意味着如果你从表中删除 医生 ,hibernate必须去创建相同的 医生 ,因为您没有让他在 约会 code> ,因为他遵循您设置的所有实体规则。因为hibernate是聪明的,他知道这一点,他会抛出一个例外,你说不要是一个矛盾,做正确的事情。

Sine you are doing appointment.setDoctor(null); it will remove object from collection (only in java as you are not explicitly or implicitly updating appointment).You have CascadeType.PERSIST on doctor that means when hibernate is going to commit the transaction it will find that appointment has association to doctor you just deleted that means if you remove that doctor from table, hibernate has to go and create same doctor as you have not told him to make appropriate changes in appointment as he follows all the entity rules set by you. Since hibernate is smart he knows this and he will throw a exception for you saying don't be an oxymoron and do the right thing.

现在有不止一个解决方案我可以想到这里

Now there are more than one solution that I can think of here


  1. 使用 cascade = {CascadeType.PERSIST,CascadeType.REMOVE} / code> cascade = CascadeType.ALL getDoctor() AppointmentRequest

如hibernate文档 here

As mentioned in hibernate document here


它在@ManyToOne或
@ManyToMany关联上启用级联通常没有意义。级联对于@OneToOne和
@OneToMany关联通常很有用。

It doesn't usually make sense to enable cascade on a @ManyToOne or @ManyToMany association. Cascade is often useful for @OneToOne and @OneToMany associations.

removeDoctor删除级联

由于您在上有 FetchType.EAGER 指定了这样一来,我解释了hibernate的行为,但是在 cascade com / questions / 11649249 / deleted-object-will-be-re-saved-by-cascade-remove-deleted-object-from-associat>这个问题,他们通过使用 FetchType.LAZY 不知道是否可以为您服务。

Since you have FetchType.EAGER on getDoctor() with cascade specified it is little complicated for me interpret the behaviour of hibernate but in this questions they have solved by using FetchType.LAZY am not sure if it will work out for you.

您可以执行会话。 saveOrUpdate(约会)在所有具有此医生的 AppointmentRequest 中,然后去 session.delete(doctor);

You can do session.saveOrUpdate(appointment) on all the AppointmentRequest which has this doctor and then go for session.delete(doctor);

希望您能解决您的问题。

Hope you this would solve your problem.

这篇关于Hibernate ManyToMany已删除的对象将被级联重新保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆