为了账号安全,请及时绑定邮箱和手机立即绑定

Spring JPA OneToOne FK 作为 PK Cascade.Remove

Spring JPA OneToOne FK 作为 PK Cascade.Remove

潇湘沐 2022-05-12 15:36:24
我有两张桌子,b并且a:它们具有一对一的双向关系a有一个外键来b定义这种关系这个外键也被认为是a, 和 JPA的主键@ID我想要一个级联删除,删除相关的b何时a被删除在 MySQL 中,a'sb_id是NOT NULL问题是当我A使用 JPA 存储库删除我的对象时,我会ConstraintViolationException在其外键上得到一个。我希望a和b行都被删除(巧妙地从a's 开始)。知道我想保留,我怎么能解决这个问题:我的数据库架构相同a从到的级联删除bidb是 JPA@Id的aCREATE TABLE `b` (  `dbid` int(11) NOT NULL AUTO_INCREMENT,  PRIMARY KEY (`dbid`),);CREATE TABLE `a` (  `b_id` int(11) NOT NULL,  KEY `b_fk` (`b_id`),  CONSTRAINT `b_fk` FOREIGN KEY (`b_id`) REFERENCES `b` (`dbid`),);@Entity@Table(name = "a")public class A {    @Id    @Column(name = "b_id")    @GeneratedValue(generator = "gen")    @GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name="property", value="b"))    private Integer bId;    @OneToOne(cascade = CascadeType.REMOVE)    @PrimaryKeyJoinColumn    private B b;}@Entity@Table(name = "b")public class B {    @Id    @GeneratedValue(strategy= GenerationType.IDENTITY)    @Column(name = "dbid")    private Integer id;    @OneToOne(mappedBy = "b")    private A a;}[编辑] 在回答评论和重新阅读我的问题的所有讨论之后,这些提案orphanRemoval确实在范围和工作中。
查看完整描述

3 回答

?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

如果您想删除 的对象B,只要关联的对象A被删除(这是您的愿望清单的第四点:

我想要一个级联删除,删除相关的b何时a被删除

那么您需要将映射更改A为:

@OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true)
@PrimaryKeyJoinColumn
private B b;


查看完整回答
反对 回复 2022-05-12
?
holdtom

TA贡献1805条经验 获得超10个赞

就您实现的 MySQL 方面而言,表 B 中的记录对表 A 中的任何记录都没有“知识”。在数据库中,关系是单向的

存在本机级联功能以防止外键错误,通过告诉数据库在删除记录时要做什么会使外键无处指向。删除表 A 记录不会导致任何表 B 记录中的外键错误,因此不会触发任何本机级联功能

重申;您不能保持模式相同,并且从ato级联删除b,因为您实际上没有从ato级联删除b

您还在评论中提到,一些表 B 记录可以存在而没有表 A 记录,而表 A 记录不在原始问题中

要获得您描述的表 B 记录的自动删除,您有几个关于数据库的选项:

  1. 交换关系- 删除当前外键并在表 B 中添加一个可以为空的外键列,该列引用表 A 的主键。然后您可以在此外键上进行级联删除。对于不“属于”表 A 记录的表 B 记录,保持新列为空。您还可以向此列添加唯一索引以确保一对一关系

  2. 添加数据库触发器- 删除表 A 记录时,添加删除引用的表 B 记录的数据库触发器

  3. 添加一个 DB 过程- 添加一个过程,删除表 A 记录,然后依次删除引用的表 B 记录,可能在事务中。继续前进,仅使用该过程删除表 A 记录

  4. 不要在 DB 层面解决问题- 与选项 3 基本相同,但将过程逻辑从 DB 层移到应用程序逻辑中

JPA 中可能有一些东西可以开箱即用地解决您的困境,但在幕后它将执行上述操作之一(不是选项 1,可能是选项 4)


查看完整回答
反对 回复 2022-05-12
?
白板的微信

TA贡献1883条经验 获得超3个赞

为了实现您的要求,我对您的表格进行了如下调整:


    CREATE TABLE b (

       dbid INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY

    );


    CREATE TABLE a ( 

       b_id int(11) NOT NULL PRIMARY KEY REFERENCES b(dbid) ON DELETE CASCADE

    );

CASCADE DELETE没有添加到您的 DDL 中。


这将启用级联删除。要删除删除b记录,a我在课堂上做了以下更改A:


@Entity

@Table(name = "a")

public class A {


    @Id

    @Column(name = "b_id")

    @GeneratedValue(generator = "gen")

    @GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name="property", value="b"))

    private Integer bId;


    @OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true)

    @PrimaryKeyJoinColumn

    private B b;

}


查看完整回答
反对 回复 2022-05-12
  • 3 回答
  • 0 关注
  • 119 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信