【问题标题】:Hibernate 3.6.10 doesn't cascade delete through OneToMany JoinTableHibernate 3.6.10 不会通过 OneToMany JoinTable 级联删除
【发布时间】:2013-01-22 11:41:09
【问题描述】:

我已经搞砸了这个问题并在谷歌上搜索了大约 4 天,我对 Hibernate 注释如何与 JPA 注释一起工作感到疯狂。我有两个非常简单的实体:

学生

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

}

电话

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

}

我已将整个代码粘贴到此处,以便您查看导入的来源。我认为问题就在那里。 重要提示:我使用的是 JoinTable,正如 Hibernate Docs 推荐的那样

好的!现在我用两个电话号码创建一个Student 并将其正确保存在数据库中。这将创建以下内容:

学生

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

学生电话

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

电话

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

问题来了。如果我在客户端删除一个电话号码(手机)并将分离的学生实体发送到服务器并执行更新,则休眠到以下内容:

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 (?, ?)

如您所见,它只是删除了联接表中的条目,但并未删除电话表中的电话条目本身。所以现在表格看起来像这样:

学生

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

学生电话

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

电话

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

问题:这是正常行为吗?即使级联删除和孤立删除设置为真?我怎样才能实现休眠也删除电话表中的电话号码?

更新我正在使用 PostgreSQL

【问题讨论】:

  • 发回集合时,您是否正确设置了集合中的电话 ID?因为这不是正常行为,应该从子表中正确删除。
  • 这是我曾经发生过的事情,我检查的第一件事也是如此。是的,设置正确

标签: java hibernate postgresql jpa


【解决方案1】:

在与 Hibernate 进一步合作后,我终于意识到我没有正确实现 equalshashCode 函数,导致在 CRUD 操作上 Hibernate Generated Sequence 出现一些问题。这个问题在great article 中描述(并解决了)(我认为必须阅读)

最好的问候

【讨论】:

    【解决方案2】:

    这看起来很像

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

    您正在混合使用 JPA 和休眠注释。我会坚持使用一个(最好是 JPA,但博客文章坚持使用休眠)并以这种方式建立关系:

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

    【讨论】:

    • 感谢您的提示,但不起作用。在发帖之前我已经完成了作业,我也尝试过。最好的问候
    猜你喜欢
    • 2014-11-16
    • 2020-06-25
    • 2017-06-07
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多