Hibernate 3.6.10不会通过OneToMany JoinTable级联删除 [英] Hibernate 3.6.10 doesn't cascade delete through OneToMany JoinTable

查看:99
本文介绍了Hibernate 3.6.10不会通过OneToMany JoinTable级联删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在搞这个,并用它搜索了大约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;

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

@实体
公共类学生{

@Id
@GeneratedValue
私人长学生ID;
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);
$ b $ 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(){
返回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());
返回结果;
}

@Override
public boolean equals(Object obj){
if(this == obj)return true;
if(obj == null)return false;
if(getClass()!= obj.getClass())返回false;
学生其他=(Student)obj;
if(studentId!= other.studentId)返回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;
返回true;
}

}

电话

  package com.vaannila.student; 

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

@实体
公共类电话{

@Id
@GeneratedValue
私人长phoneId;
private String phoneType;
私人字符串phoneNumber;
$ b公共电话(){
}

公用电话(字符串phoneType,字符串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());
返回结果;
}

@Override
public boolean equals(Object obj){
if(this == obj)return true;
if(obj == null)return false;
if(getClass()!= obj.getClass())返回false;
电话其他=(电话)obj;
if(phoneId!= other.phoneId)返回false;
if(phoneNumber == null){
if(other.phoneNumber!= null)return false;
}
else if(!phoneNumber.equals(other.phoneNumber))返回false;
if(phoneType == null){
if(other.phoneType!= null)return false;
}
else if(!phoneType.equals(other.phoneType))return false;
返回true;
}

}

我粘贴了整个代码在这里你可以看到进口的来源。我认为问题在那里。 重要:我使用的是 JoinTable ,因为Hibernate Docs建议使用



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

学生

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

student_phone

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

手机

  phoneid |电话号码| phonetyp 
--------- + ------------- + ---------
4 | 9889343423 |手机
3 | 32354353 |房屋
(2行)

问题出在这里。如果我删除客户端中的一个电话号码(移动设备),并将分离的学生实体发送到服务器并执行更新,那么Hibernate会执行以下操作:

  Hibernate:更新Student set studentName =? studentId =? 
休眠:更新电话机phoneNumber =?,phoneType =? phoneId =?
Hibernate:从STUDENT_PHONE中删除STUDENT_ID =?
Hibernate:插入STUDENT_PHONE(STUDENT_ID,PHONE_ID)值(?,?)

您可以看到,它只是删除连接表中的条目,但不会删除电话表中的电话条目本身。所以现在这些表格看起来像这样:

学生

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

student_phone

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

手机

  phoneid |电话号码| phonetyp 
--------- + ------------- + ---------
4 | 9889343423 |手机
3 | 32354353 |房屋
(2行)

问题:是正常行为吗?即使级联删除和孤儿删除设置为true?我如何才能实现Hibernate删除电话表中的电话号码?

更新我正在使用PostgreSQL

解决方案

经过进一步的Hibernate工作后,我意识到我没有正确实现 equals hashCode 函数在CRUD操作中导致Hibernate生成序列的一些麻烦。该问题在伟大的文章(我认为必须阅读)



最好的祝愿


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. 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

Ok! Now I create a Student with two Phone numbers and save it correctly in the database. This creates the following:

student

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

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_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? How I can achieve that Hibernate delete the phone number in phone table too?

UPDATE I'm using 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. The problem is described (and solved) in this great article (a must read, in my opinion)

Best regards

这篇关于Hibernate 3.6.10不会通过OneToMany JoinTable级联删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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