简体   繁体   English

Hibernate 3.6.10不会通过OneToMany JoinTable级联删除

[英]Hibernate 3.6.10 doesn't cascade delete through OneToMany JoinTable

I've been messing with this and googling it for about 4 days and I'm getting crazy about how Hibernate annotations work with JPA annotations. 我一直在搞乱这个并且谷歌搜索它大约4天而且我对于Hibernate注释如何与JPA注释一起工作变得疯狂。 I have two very simple entities: 我有两个非常简单的实体:

Student 学生

package com.vaannila.student;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@Entity
public class Student {

    @Id
    @GeneratedValue
    private long studentId;
    private String studentName;
    @OneToMany(orphanRemoval = true)
    @Cascade(CascadeType.ALL)
    @JoinTable(name = "STUDENT_PHONE", joinColumns = { @JoinColumn(name = "STUDENT_ID") }, inverseJoinColumns = { @JoinColumn(name = "PHONE_ID") })
    private Set<Phone> studentPhoneNumbers = new HashSet<Phone>(0);

    public Student() {
    }

    public Student(String studentName, Set<Phone> studentPhoneNumbers) {
        this.studentName = studentName;
        this.studentPhoneNumbers = studentPhoneNumbers;
    }

    public long getStudentId() {
        return this.studentId;
    }

    public void setStudentId(long studentId) {
        this.studentId = studentId;
    }

    public String getStudentName() {
        return this.studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public Set<Phone> getStudentPhoneNumbers() {
        return this.studentPhoneNumbers;
    }

    public void setStudentPhoneNumbers(Set<Phone> studentPhoneNumbers) {
        this.studentPhoneNumbers = studentPhoneNumbers;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (studentId ^ (studentId >>> 32));
        result = prime * result + ((studentName == null) ? 0 : studentName.hashCode());
        result = prime * result + ((studentPhoneNumbers == null) ? 0 : studentPhoneNumbers.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Student other = (Student) obj;
        if (studentId != other.studentId) return false;
        if (studentName == null) {
            if (other.studentName != null) return false;
        }
        else if (!studentName.equals(other.studentName)) return false;
        if (studentPhoneNumbers == null) {
            if (other.studentPhoneNumbers != null) return false;
        }
        else if (!studentPhoneNumbers.equals(other.studentPhoneNumbers)) return false;
        return true;
    }

}

Phone 电话

package com.vaannila.student;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Phone {

    @Id
    @GeneratedValue
    private long phoneId;
    private String phoneType;
    private String phoneNumber;

    public Phone() {
    }

    public Phone(String phoneType, String phoneNumber) {
        this.phoneType = phoneType;
        this.phoneNumber = phoneNumber;
    }

    public long getPhoneId() {
        return this.phoneId;
    }

    public void setPhoneId(long phoneId) {
        this.phoneId = phoneId;
    }

    public String getPhoneType() {
        return this.phoneType;
    }

    public void setPhoneType(String phoneType) {
        this.phoneType = phoneType;
    }

    public String getPhoneNumber() {
        return this.phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (phoneId ^ (phoneId >>> 32));
        result = prime * result + ((phoneNumber == null) ? 0 : phoneNumber.hashCode());
        result = prime * result + ((phoneType == null) ? 0 : phoneType.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Phone other = (Phone) obj;
        if (phoneId != other.phoneId) return false;
        if (phoneNumber == null) {
            if (other.phoneNumber != null) return false;
        }
        else if (!phoneNumber.equals(other.phoneNumber)) return false;
        if (phoneType == null) {
            if (other.phoneType != null) return false;
        }
        else if (!phoneType.equals(other.phoneType)) return false;
        return true;
    }

}

I've pasted the whole code here so you can see where the imports come from. 我在这里粘贴了整个代码,以便您可以看到导入的来源。 I think the problem is there. 我认为问题在那里。 Important : I'm using a JoinTable as Hibernate Docs recommends 重要提示 :我正在使用JoinTable因为Hibernate Docs建议使用

Ok! 好! Now I create a Student with two Phone numbers and save it correctly in the database. 现在我创建一个有两个电话号码的Student ,并将其正确保存在数据库中。 This creates the following: 这会创建以下内容:

student 学生

 studentid | studentname
-----------+-------------
         2 | foo
(1 rows)

student_phone student_phone

 student_id | phone_id
------------+---------
          2 |        3
          2 |        4
(2 rows)

phone 电话

 phoneid | phonenumber | phonetyp
---------+-------------+---------
       4 | 9889343423  | mobile
       3 | 32354353    | house
(2 rows)

Here comes the problem. 这就是问题所在。 If I delete one of the phone numbers (mobile) in client side and send the detached student entity to the server and perform an update, Hibernate to the following: 如果我删除客户端中的一个电话号码(移动)并将分离的学生实体发送到服务器并执行更新,请执行以下操作:

Hibernate: update Student set studentName=? where studentId=?
Hibernate: update Phone set phoneNumber=?, phoneType=? where phoneId=?
Hibernate: delete from STUDENT_PHONE where STUDENT_ID=?
Hibernate: insert into STUDENT_PHONE (STUDENT_ID, PHONE_ID) values (?, ?)

As you can see, it just deletes the entry in the join table but does not delete the phone entry itself in the phone table. 如您所见,它只是删除了连接表中的条目,但没有删除电话表中的电话条目本身。 So now the tables look like this: 所以现在这些表看起来像这样:

student 学生

 studentid | studentname
-----------+-------------
         2 | foo
(1 rows)

student_phone student_phone

 student_id | phone_id
------------+---------
          2 |        3
(1 rows)

phone 电话

 phoneid | phonenumber | phonetyp
---------+-------------+---------
       4 | 9889343423  | mobile
       3 | 32354353    | house
(2 rows)

Question: Is that the normal behaviour? 问题: 这是正常行为吗? Even if cascading delete and orphan removal is set to true? 即使级联删除和孤立删除设置为true? How I can achieve that Hibernate delete the phone number in phone table too? 我怎样才能实现Hibernate删除手机表中的电话号码呢?

UPDATE I'm using PostgreSQL 更新我正在使用PostgreSQL

After further work with Hibernate finally I realise I wasn't implementing correctly equals and hashCode functions causing some troubles with Hibernate Generated Sequence on CRUD operations. 在进一步使用Hibernate之后,我终于意识到我没有正确实现equalshashCode函数,导致在CRUD操作上使用Hibernate Generated Sequence出现一些问题。 The problem is described (and solved) in this great article (a must read, in my opinion) 在这篇伟大的文章中描述(并解决了)这个问题(在我看来必须阅读)

Best regards 最好的祝福

This looks very similar to 这看起来非常相似

http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/ http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/

You are mixing JPA and hibernate annotations. 您正在混合JPA和hibernate注释。 I would stick with one (preferably JPA, but the blog posts sticks with hibernate) and had the relationship this way: 我会坚持使用一个(最好是JPA,但博客文章坚持使用hibernate)并且这样关系:

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM