Spring boot delete 没有级联,它将外键设置为 null,然后在 null 约束上失败
Posted
技术标签:
【中文标题】Spring boot delete 没有级联,它将外键设置为 null,然后在 null 约束上失败【英文标题】:Spring boot delete is not cascading it is setting the foriegn key to null and then failing on a null constraint 【发布时间】:2020-02-28 04:14:32 【问题描述】:在 Spring Boot 中使用 deleteById 和一对多关系,生成的查询会尝试在引用的实体中将外键设置为 null 而不是删除它们。我正在使用默认存储库 deleteById
我已经在实体中的外键定义上将 Cascadetype 设置为 ALL 并将 OrpahnRemoval 设置为 true,并且我在创建表的 DDL 中设置了 ON DELETE CASCADE。
这里是控制器类中的删除操作
@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
【问题讨论】:
【参考方案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
【讨论】:
你成就了我的一天。谢谢。以上是关于Spring boot delete 没有级联,它将外键设置为 null,然后在 null 约束上失败的主要内容,如果未能解决你的问题,请参考以下文章
Java Spring boot hibernate删除级联数据
Spring Boot + Spring Security 应用程序中 POST/PUT/DELETE 请求的 403 响应