有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java无法删除父实体,因为在双向映射情况下存在子引用

正如我在标题中提到的,当我试图删除一个“父”实体时遇到了问题,因为它的子引用违反了数据完整性。我认为这个错误与实体的某些缺失配置有关,但我无法获得缺失的内容。 是否可以让understand to Hibernate/JPA先删除子引用,然后再删除父引用?我希望继续使用这个关系和Spring数据JPA存储库

如果JPA/Hibernate允许的话,我希望避免显式使用实体管理器来处理这些情况(因此我不想“手动”删除它们),因为自动查询生成的Spring JPA对所有的“select/count/”都有很大的帮助案例

父子关系在两侧都映射,其中:

  1. 父级不拥有列,因此映射由“mappedBy”配置
  2. 子级有一个复合键,其中一列通过其id链接到父级
  3. 配置由JPA注释进行

当hibernate执行其查询时,它找不到某些子项对试图删除的记录具有外键约束,因此它希望先执行“父项删除”,然后移动到“子项”

原因是:

Referential integrity constraint violation: "FK_PARENT_ID_PARENT: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (1)"; SQL statement: delete from Parent where id=? [23503-200]

数据库表由外部SQL脚本创建,hibernate配置为避免ddl生成。这是一项要求,无法修改,因此无法删除子表中的外键和id约束

在下面,您可以找到实体的Java定义,这里我尝试给出配置的概述

母公司拥有一家@OneToMany

  • mappedBy=子对象中字段的名称
  • fetch=FetchType。急切的
  • 级联=级联类型。全部
  • 孤立删除=真

子实体拥有@ManyToOne plus@join列,其中:

  • 可选=错误
  • name=表列的名称

下面是Java代码

家长。java

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.Objects;
import java.util.Set;

@Entity
public class Parent {
    @Id
    @Column
    private long id;

    @Column
    private String name;

    @OneToMany(mappedBy = "parent",
            fetch = FetchType.EAGER,
            cascade = CascadeType.ALL,
            orphanRemoval = true)
    private Set<Child> children;

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Child> getChildren() {
        return children;
    }

    public void setChildren(Set<Child> children) {
        this.children = children;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Parent parent = (Parent) o;
        return id == parent.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

孩子。java

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.util.Objects;

@Entity
@IdClass(ChildIdentifier.class)
public class Child {
    @Id
    @Column
    private long id;

    @Column
    private String name;

    @Id
    @JoinColumn(nullable = false,
            name ="parent_id",
            referencedColumnName = "id")
    @ManyToOne(optional = false)
    private Parent parent;

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Child child = (Child) o;
        return id == child.id &&
                Objects.equals(parent, child.parent);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, parent);
    }
}

儿童识别码。java

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;
import java.util.Objects;

public class ChildIdentifier implements Serializable {
    @Id
    @Column
    private long id;
    @JoinColumn(nullable = false,
            name ="parent_id",
            referencedColumnName = "id")
    @ManyToOne(optional = false)
    private Parent parent;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ChildIdentifier that = (ChildIdentifier) o;
        return id == that.id &&
                Objects.equals(parent, that.parent);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, parent);
    }

    public long getId() {
        return id;
    }

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

    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }
}

共 (1) 个答案

  1. # 1 楼答案

    我解决了问题。删除不是通过实体管理器的删除功能完成的

    执行删除操作的存储库由@Query annotation示例@Query(“从父项删除,其中id=:id”))实现。 我还没有完全理解这种行为背后的原因,但JPQL并没有导致正确的订单删除

    要解决此问题,请执行以下操作:

    1. @查询注释已从存储库方法中删除
    2. 方法已重命名为deletedById,以匹配JPA命名约定

    此更改允许Spring Data JPA通过其id检索实体,然后执行实体管理器删除实体功能