java - Spring boot 删除不是级联,而是将外键设置为 null,然后在 null 约束上失败

标签 java postgresql spring-boot

在Spring Boot中使用deleteById与一对多关系生成的查询尝试将引用实体中的外键设置为null,而不是删除它们。我正在使用默认存储库deleteById

我已在实体中的外键定义中将 Cascadetype 设置为 ALL,将 OrpahnRemoval 设置为 true,并在创建表的 DDL 中设置 ON DELETE CASCADE。

这里是 Controller 类中的删除操作

@Transactional
@DeleteMapping("transferImage/{imageId}")
public void  deleteTransferImage(@PathVariable int imageId) {
    repository.deleteById(imageId);
}

这是从父实体到子实体的引用

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, OrphanRemoval = true)
@JoinColumn(name = "TRANSFER_IMAGE_ID")
private List<TransferPartition> partitions = new ArrayList<>();

这是子实体中外键的定义

@JsonIgnore
@ManyToOne
@JoinColumn(name = "TRANSFER_IMAGE_ID", referencedColumnName = "TRANSFER_IMAGE_ID")
private TransferImage image;

这是用于创建两个表的 DDL

CREATE TABLE TRANSFER_IMAGE (
TRANSFER_IMAGE_ID       SERIAL CONSTRAINT TRANSFER_IMAGE_PK PRIMARY KEY,
IMAGE_NAME              VARCHAR(50) CONSTRAINT TRANSFER_IMAGE_NAME_UK UNIQUE NOT NULL ,
REQUESTED_PART_SIZE_MB  INTEGER NOT NULL,
SIZE_BYTES              INTEGER NOT NULL,
IMAGE_MD5_HASH          VARCHAR(100),
NUMBER_PARTITIONS       INTEGER,
DELETED                 BOOLEAN  NOT NULL
);

CREATE TABLE TRANSFER_PARTITION (
TRANSFER_PARTITION_ID   SERIAL CONSTRAINT TRANSFER_PARTITION_PK PRIMARY KEY,
TRANSFER_IMAGE_ID       INTEGER NOT NULL CONSTRAINT TRANSFER_PARTITION_IMAGE_FK REFERENCES TRANSFER_IMAGE ON DELETE CASCADE ON UPDATE CASCADE,
PARTITION_NUMBER        INTEGER NOT NULL,
PARTITION_MD5_HASH      VARCHAR(100) NOT NULL,
SIZE_BYTES              INTEGER NOT NULL
);

这是出现在日志中的查询

 Hibernate:
  select
    transferim0_.transfer_image_id as transfer1_13_0_,
    transferim0_.deleted as deleted2_13_0_,
    transferim0_.image_md5_hash as image_md3_13_0_,
    transferim0_.image_name as image_na4_13_0_,
    transferim0_.number_partitions as number_p5_13_0_,
    transferim0_.requested_part_size_mb as requeste6_13_0_,
    transferim0_.size_bytes as size_byt7_13_0_,
    partitions1_.transfer_image_id as transfer5_14_1_,
    partitions1_.transfer_partition_id as transfer1_14_1_,
    partitions1_.transfer_partition_id as transfer1_14_2_,
    partitions1_.transfer_image_id as transfer5_14_2_,
    partitions1_.partition_number as partitio2_14_2_,
    partitions1_.partition_md5_hash as partitio3_14_2_,
    partitions1_.size_bytes as size_byt4_14_2_
from
    transfer_image transferim0_
left outer join
   transfer_partition partitions1_
       on transferim0_.transfer_image_id=partitions1_.transfer_image_id
where
      transferim0_.transfer_image_id=?
Hibernate:
update
    transfer_partition
 set
     transfer_image_id=null
 where
     transfer_image_id=?

我期望当我通过主键删除父实体时,引用父实体 (TransferImage) 的所有子实体 (TransferPartition) 都会被删除。相反,我收到引用外键列的空约束错误。在我看来,生成的 SQL 将外键列设置为 null,而不是删除该行。

ERROR: null value in column "transfer_image_id" violates not-null constraint
Detail: Failing row contains (1, null, 1, asdfaa1-1, 20000000).

如果我从 psql 提示符下的 transfer_image 表中删除图像,删除级联会正确,并且引用的分区将被删除。

delete  from transfer_image i where i.transfer_image_id = 1

最佳答案

您的问题在于 TransferImage 类中外键关系的定义。

而不是

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, OrphanRemoval = true)
@JoinColumn(name = "TRANSFER_IMAGE_ID")
private List<TransferPartition> partitions = new ArrayList<>();

你应该使用

@OneToMany(mappedBy="image", cascade = CascadeType.ALL, fetch = FetchType.EAGER, OrphanRemoval = true)
private List<TransferPartition> partitions = new ArrayList<>();

另请参阅https://www.baeldung.com/hibernate-one-to-many

关于java - Spring boot 删除不是级联,而是将外键设置为 null,然后在 null 约束上失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58666444/

相关文章:

java - Apache POI api 和 Apache Tika Api 之间的区别?

sql - 如何使用有序查询的结果调用函数

java - 在从 jQuery ajax 调用的 Spring REST Controller 中解析请求 JSON

java - 如何处理现实项目中的运行时异常

java - 如何处理在 Android 中小屏幕尺寸下被截断的大 textView?

sql - 使用触发器的 PostgreSQL 审计历史

spring - 在gradle 2.12和2.13中使用spring-boot的奇怪错误

java - 绑定(bind) ConfigurationProperties 时出现 NullPointerException (Spring Boot)

java - H2 使用线程时内存数据库不一致

python - 带边界的 SQLAlchemy 求和函数