JPA: 单向多对一和级联删除

假设我有如下 单向的 @ManyToOne关系:

@Entity
public class Parent implements Serializable {


@Id
@GeneratedValue
private long id;
}


@Entity
public class Child implements Serializable {


@Id
@GeneratedValue
private long id;


@ManyToOne
@JoinColumn
private Parent parent;
}

如果我有一个父 P 和子 C1... Cn引用回 P,有没有一个干净漂亮的方法在 JPA 中自动删除子 C1... Cn当 P 被删除(即 entityManager.remove(P)) ?

我所寻找的是类似于 SQL 中的 ON DELETE CASCADE的功能。

140795 次浏览

JPA 中的关系总是单向的,除非您在两个方向上将父级与子级关联起来。从父级到子级的级联移除操作将需要从父级到子级的关系(而不仅仅是相反)。

因此,你需要这样做:

  • 或者,将单向 @ManyToOne关系更改为双向 @ManyToOne,或者将单向 @OneToMany更改为双向 @ManyToOne。然后您可以级联 REMOVE 操作,这样 EntityManager.remove将删除父级和子级。还可以将 orphanRemoval指定为 true,以便在父集合中的子实体设置为 null 时删除任何孤立的子实体,即在子实体不存在于任何父集合中时删除子实体。
  • 或者,将子表中的外键约束指定为 ON DELETE CASCADE。在调用 EntityManager.remove(parent)之后,需要调用 EntityManager.clear(),因为持久化上下文需要刷新——子实体在数据库中被删除后,不应该存在于持久化上下文中。

创建一个双向关系,像这样:

@Entity
public class Parent implements Serializable {


@Id
@GeneratedValue
private long id;


@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
private Set<Child> children;
}

@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

给出的注释对我有用。可以试一试

例如:-

     public class Parent{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="cct_id")
private Integer cct_id;
@OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true)
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private List<Child> childs;
}
public class Child{
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="cct_id")
private Parent parent;
}

如果使用 hibernate 作为 JPA 提供程序,则可以使用注释 @OnDelete。此注释将添加到关系中的触发器 ON DELETE CASCADE,该触发器将子元素的删除委托给数据库。

例如:

public class Parent {
   

@Id
private long id;


}




public class Child {
        

@Id
private long id;
  

@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
}
     

使用此解决方案,从子级到父级的单向关系足以自动删除所有子级。这个解决方案不需要任何侦听器等。另外,像 DELETE FROM Parent WHERE id = 1这样的 JPQL 查询将删除子级。

我在单向@ManytoOne 中看到,删除不如预期。 当父节点被删除时,理想情况下子节点也应该被删除,但是只有父节点被删除,子节点没有被删除,并且作为孤儿留下

使用的技术是 Spring Boot/Spring Data JPA/Hibernate

Sprint Boot: 2.1.2. 版本

Spring Data JPA/Hibernate 用于删除行

parentRepository.delete(parent)

ParentRepository 扩展了标准 CRUD 存储库,如下所示 ParentRepository extends CrudRepository<T, ID>

下面是我的实体类

@Entity(name = “child”)
public class Child  {


@Id
@GeneratedValue
private long id;


@ManyToOne( fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = “parent_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
}


@Entity(name = “parent”)
public class Parent {


@Id
@GeneratedValue
private long id;


@Column(nullable = false, length = 50)
private String firstName;




}

用这种方法只删除一边

    @ManyToOne(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
//  @JoinColumn(name = "qid")
@JoinColumn(name = "qid", referencedColumnName = "qid", foreignKey = @ForeignKey(name = "qid"), nullable = false)
// @JsonIgnore
@JsonBackReference
private QueueGroup queueGroup;

您不需要使用双向关联来代替代码,只需要添加 CascaType。作为属性删除到 ManyToOne 注释,然后使用@OnDelete (action = OnDeleteAction.CASCADE) ,它对我来说很好用。