休眠父级联删除单向子错误

时间:2019-05-12 18:31:00

标签: java hibernate

我有一个非常简单的Spring Boot测试

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @Bean
    public CommandLineRunner demo(ParentRepository parentRepo, ChildRepository childRepo) {
        return (args) -> {
            Parent parent = new Parent("Father");
            parent = parentRepo.save(parent);
            childRepo.save(new Child("Father", "Jack"));

            for (Child child : childRepo.findAll()) {
                System.out.println(child);
            }

            parentRepo.findById(parent.getName()).ifPresent(p -> {
                System.out.println(p);
    1.          p.getChildren().clear();//update child set parent_name=null NULL not allowed for column "PARENT_NAME";
    2.          p.setChildren(null);    //A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: springtest.Parent.children
                parentRepo.save(p);
            });

            for (Parent p : parentRepo.findAll()) {
                System.out.println(p);
            }
        };
    }

}

父实体

@Entity
public class Parent {
    @Id
    @Column(name = "NAME", nullable = false)
    private String name;

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

    protected Parent() {}

    public Parent(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

    @Override
    public String toString() {
        return "Parent[name=" + name + ", children=" + children.size() + "]";
    }

}

子实体

@Entity
public class Child {
    @Id
    @Column(name = "NAME", nullable = false)
    private String name;

    @Column(name = "PARENT_NAME", nullable = false)
    private String parentName;

    protected Child() {}

    public Child(String parentName, String name) {
        this.parentName = parentName;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Child[parentName=" + parentName + ", name=" + name + "]";
    }

}

ParentRepository

public interface ParentRepository extends CrudRepository<Parent, String> {}

ChildRepository

public interface ChildRepository extends CrudRepository<Child, String> {}

我想从父实体中删除子代。链接使用单向,并且拥有实体是父级。我尝试调用1。getChildren().clear(),但是休眠状态最终生成了一条更新语句,该语句将parent_name设置为null(而不是delete,其中parent_name =“ Father”),这违反了Child表中的不可为空的约束。

然后我尝试呼叫2。setChildren(null),这次它给出了异常A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

您如何解决上述问题以使孩子撤离工作正常?

1 个答案:

答案 0 :(得分:1)

作为拥有实体,“父母”应该是唯一修改外键的人。因此,我将从“ Child”中删除parentName。

所以我会这样更改它:

@Entity
public class Child {
    @Id
    @Column(name = "NAME", nullable = false)
    private String name;

    protected Child() {}

    public Child(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Child[name=" + name + "]";
    }
}

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @Bean
    public CommandLineRunner demo(ParentRepository parentRepo, ChildRepository childRepo) {
        return (args) -> {
            Parent parent = new Parent("Father");
            parent.add(new Child("Jack"));
            parent = parentRepo.save(parent); //the child is saved because of the cascading


            for (Child child : childRepo.findAll()) {
                System.out.println(child);
            }

            parentRepo.findById(parent.getName()).ifPresent(p -> {
                System.out.println(p);
                p.getChildren().clear();
                parentRepo.save(p); 
            });

            for (Parent p : parentRepo.findAll()) {
                System.out.println(p);
            }
        };
    }

}