春季JPA OneToOne FK作为PK级联。删除

时间:2019-01-19 14:12:10

标签: java mysql hibernate spring-boot jpa

我有两个表,ba

  • 它们具有一对一的双向关系
  • a具有b的外键,用于定义这种关系
  • 此外键也被视为a和JPA @ID的主键
  • 我想要一个级联删除,以便在删除b时删除相关的a
  • 在MySQL中,a的{​​{1}}是b_id

问题是,当我使用JPA存储库删除NOT NULL对象时,我在其外键上得到了A。 我希望同时删除ConstraintViolationExceptiona行(最好从b的行开始)。

在知道自己想保留的情况下,我该如何解决:

  • 我的数据库架构相同
  • aa的级联删除
  • b ID为b的JPA @Id
a
CREATE 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;
}

[EDIT]在回答了所有答案并重新阅读了我的问题之后,带有@Entity @Table(name = "b") public class B { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "dbid") private Integer id; @OneToOne(mappedBy = "b") private A a; } 的提案确实在范围和工作中。

5 个答案:

答案 0 :(得分:1)

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

  

我想要一个级联删除,以便在删除b时删除相关的a

然后,您需要将A中的映射更改为:

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

答案 1 :(得分:1)

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

    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;
}

效果很好。希望对您有所帮助。

在此处找到指向有效的solution的链接。

答案 2 :(得分:1)

仅从实现的MySQL方面来看,表B中的记录没有表A中任何记录的“知识”。在数据库中,关系是单向的

存在本机级联功能以防止外键错误,方法是通过告诉DB删除记录时该怎么做将使外键指向无处。删除表A记录不会在任何表B记录中引起外键错误,因此不会触发任何本机级联功能

重申; 您无法保持架构相同,也无法将级联从a移至b,因为实际上并没有级联从a移至b

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

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

  1. 交换关系-删除当前的外键,并在表B中添加可为空的外键列,该列引用表A的主键。然后,您可以在此外键上进行级联删除。对于不“属于”表A记录的表B记录,使新列为空。您还可以在此列中添加唯一索引,以确保一对一关系
  2. 添加数据库触发器-删除表A记录后,添加数据库触发器以删除引用的表B记录
  3. 添加数据库过程-添加一个过程,该过程依次删除表A记录和引用的表B记录(可能在事务中)。向前,仅使用该过程删除表A记录
  4. 不能在数据库级别解决问题-与选项3基本相同,但是将过程逻辑从数据库层移到应用程序逻辑中

JPA中可能有一些解决方案可以立即解决您的难题,但是在幕后,它将执行上述操作之一(不是选项1,可能是选项4)

答案 3 :(得分:0)

您可以在B类中尝试添加以下内容吗?

@OneToOne(mappedBy = "b", cascade = CascadeType.REMOVE)
private A a;

此外,如果在数据库中您只有一个外键“ a有一个到b的外键”,那么您也可以从b到a都有一个外键。

答案 4 :(得分:0)

尝试以下代码-

@OneToOne(mappedBy = "b",cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval=true )
private A a;