ОШИБКА H2: Нарушение ограничения ссылочной целостности — Переход из режима гибернации один к одному

#java #hibernate #jpa #foreign-keys #h2

Вопрос:

У меня есть две сущности (Инструктор, InstructorDetail), которые имеют отношение один к одному.

instructor_detail_id сущности Instructor имеет внешний ключ к столбцу идентификатора InstructorDetail. Итак, согласно моему требованию, когда Инструктор удаляется, соответствующий инструктор также должен быть удален, но не наоборот. Теперь, когда я пытаюсь удалить instructorDetail, он выдает ошибку ограничения целостности ссылок.

Примечание: Я использую H2 db.

Ниже приведены фрагменты кода.

Инструктор

 import javax.persistence.*;

@Table(name="instructor")
@Entity
public class Instructor implements IdentityMarker<Integer>{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="instructor_id")
    private int id;

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

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

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "instructor_detail_id")//, referencedColumnName = "id")
    private InstructorDetail instructorDetail;


    public Instructor(){

    }
    public Instructor(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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;
    }

    public InstructorDetail getInstructorDetail() {
        return instructorDetail;
    }

    public void setInstructorDetail(InstructorDetail instructorDetail) {
        this.instructorDetail = instructorDetail;
    }

    public Integer getReference() {
        return id;
    }

    public void setReference(Integer id){ this.id = id;}

    @Override
    public String toString() {
        return "Instructor{"  
                "id="   id  
                ", name='"   name   '''  
                ", email='"   email   '''  
                ", instructorDetail="   instructorDetail  
                '}';
    }
}
 

ИнструкторДетайл

 import javax.persistence.*;

@Table(name="instructor_detail")
@Entity
public class InstructorDetail implements IdentityMarker<Integer>{

    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name="youtube_link")
    private String youtubeLink;

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

    @OneToOne(cascade = {
                            CascadeType.DETACH,
                            CascadeType.MERGE,
                            CascadeType.PERSIST,
                            CascadeType.REFRESH
                        },
              mappedBy = "instructorDetail")
    // this bi-directional relationship enables us to get the instructor when an instructionDetail is loaded.
    private Instructor instructor;

    public InstructorDetail(){
    }

    public InstructorDetail(String youtubeLink, String hobby){
        this.youtubeLink = youtubeLink;
        this.hobby = hobby;
    }

    public int getId() {
        return id;
    }

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

    public String getYoutubeLink() {
        return youtubeLink;
    }

    public void setYoutubeLink(String youtubeLink) {
        this.youtubeLink = youtubeLink;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public Instructor getInstructor() {
        return instructor;
    }

    public void setInstructor(Instructor instructor) {
        this.instructor = instructor;
    }

    public Integer getReference() {
        return id;
    }

    public void setReference(Integer id){ this.id = id;}

    @Override
    public String toString() {
        return "InstructorDetail{"  
                "id="   id  
                ", youtubeLink='"   youtubeLink   '''  
                ", hobby='"   hobby   ''' 
                '}';
    }

    @PreRemove
    private void preRemove() {
        System.out.println("pre remove call");
       instructor.setInstructorDetail(null);
    }
}
 

Ниже приведен клиентский код

 private static void deleteInstructorDetail(){
        InstructorDetailDao instructorDetailDao = new InstructorDetailDaoImpl();

        InstructorDetail instructorDetail = instructorDetailDao.getInstructorDetail(2);
        Instructor instructor = instructorDetail.getInstructor();


        System.out.println("Instructor: "   instructor);

        boolean b = instructorDetailDao.deleteInstructorDetail(instructorDetail);

        assert b == true: "InstructorDetail is not deleted!";

        System.out.println("Trying to load Instructor.. It should be deleted!");

        InstructorDao instructorDao = new InstructorDaoImpl();
        instructor = instructorDao.getInstructor(instructor.getId());

        assert instructor != null: "Instructor also got deleted!";

    }
 

Любая помощь будет признательна! Заранее спасибо.

Комментарии:

1. Использование CascadeType.REMOVE в классе InstructorDetail для атрибута инструктора должно исправить это.

2. На самом деле я не собираюсь удалять инструктора при удалении объекта instructorDetail.