Spring Data JPA:无法在MySQL中使用ON delete CASCADE和外键删除OneToOne关系中



我使用Spring Data JPA来映射应用程序中两个实体之间的OneToOne关系。实体是DM和DM_DATA,其中每个DM记录都有一个对应的DM_DATA记录。

DM表对DM_DATA表有一个外键约束,使用DM_DATA_ID列映射到DMD_DATA_ID (DM_DATA中的主键)。关系是在JPA实体中定义的,在DM实体上使用@OneToOne和@JoinColumn注释,在DM_DATA实体上使用@OneToOne(mappedBy = "dmData")注释。

我还在DM实体中的@OneToOne注释中添加了CASCADE选项,以启用级联删除。

父:

@Entity
@Table(name = "DM")
public class FileDm {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "DM_FILE_ID")
private long id;
@OneToOne(
fetch = FetchType.EAGER,
cascade = {CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REMOVE},
orphanRemoval = true
)
@JoinColumn(name = "DMD_DATA_ID", referencedColumnName = "DMD_DATA_ID")
private DmData dmData;
@ManyToOne(optional=true) 
@JoinColumn(name="DM_DCMT_ID", nullable=true)
private DmType dmType;
...
}

孩子:

@Entity
@Table(name = "DM_DATA")
public class DmData {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "DMD_DATA_ID")
private long code;
@OneToOne(mappedBy = "dmData")
private FileDm fileDm;
@Column(name = "DMD_DATA")
private String data;
...
}

我还写了一个sql脚本来改变DB方案并执行迁移:

ALTER TABLE DM ADD COLUMN DM_DATA_ID bigint(20);
CREATE TABLE DM_DATA (
DMD_DATA_ID bigint(20) NOT NULL AUTO_INCREMENT,
TEMP_DATA_ID bigint(20) NOT NULL,
DMD_DATA longblob,
PRIMARY KEY (DMD_DATA_ID)
) ENGINE=InnoDB CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
INSERT INTO DM_DATA(TEMP_DATA_ID, DMD_DATA)
(SELECT d.DM_FILE_ID, d.DM_DATA
FROM DM d
WHERE d.DM_DATA IS NOT NULL);
UPDATE DM d
INNER JOIN DM_DATA dd
ON d.DM_FILE_ID = dd.TEMP_DATA_ID
SET d.DM_DATA_ID = dd.DMD_DATA_ID;
ALTER TABLE DM_DATA DROP TEMP_DATA_ID;
ALTER TABLE DM DROP DM_DATA;
所以我最终得到了这些DB方案:
DM | CREATE TABLE `DM` (
`DM_FILE_ID` bigint(20) NOT NULL AUTO_INCREMENT,
`DM_DATA_ID` bigint(20) DEFAULT NULL,
`DM_DCMT_ID` varchar(3) DEFAULT NULL,
PRIMARY KEY (`DM_FILE_ID`),
KEY `FK_DM_DMTYPE_idx` (`DM_DCMT_ID`),
CONSTRAINT `FK_DM_DMTYPE` FOREIGN KEY (`DM_DCMT_ID`) REFERENCES `DMTYPE` (`DCMT_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
CONSTRAINT `FK_DM_DATA_ID` FOREIGN KEY (`DM_DATA_ID`) REFERENCES `DM_DATA` (`DMD_DATA_ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci |
| DM_DATA | CREATE TABLE `DM_DATA` (
`DMD_DATA_ID` bigint(20) NOT NULL AUTO_INCREMENT,
`DMD_DATA` varchar(255) DEFAULT NULL,
PRIMARY KEY (`DMD_DATA_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci |

然而,当我通过存储库方法或通过从db删除语句删除DM记录时,DM_DATA记录不会被删除.

我尝试使用DMD_DATA_ID列将外键约束添加到DM_DATA表,但这并没有解决问题。我还尝试切换外键关系的方向,但这导致插入新记录时出现不同的错误。

是否有任何方法可以正确配置JPA中的OneToOne关系并在sql脚本中镜像它以启用子实体的级联删除?

我通过改变关系的方向来解决这个问题:

父:

@OneToOne(
mappedBy = "fileDm",
fetch = FetchType.EAGER,
cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE },
orphanRemoval = true
)
private DmData dmData;

孩子:

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DMD_FILE_ID")
private FileDm fileDm;

在sql模式定义和迁移脚本中,我将TEMP_DATA_ID更改为DMD_FILE_ID并添加了外键约束

CREATE TABLE DM_DATA (
DMD_DATA_ID bigint(20) NOT NULL AUTO_INCREMENT,
DMD_FILE_ID bigint(20),
DMD_DATA longblob,
PRIMARY KEY (DMD_DATA_ID)
) ENGINE=InnoDB CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
INSERT INTO DM_DATA(DMD_FILE_ID, DMD_DATA)
(SELECT d.DM_FILE_ID, d.DM_DATA
FROM DM d
WHERE d.DM_DATA IS NOT NULL);
ALTER TABLE DM DROP DM_DATA;
ALTER TABLE OH_DM_DATA
ADD CONSTRAINT FK_DM_DATA
FOREIGN KEY (DMD_FILE_ID)
REFERENCES DM (DM_FILE_ID)
ON DELETE CASCADE
ON UPDATE CASCADE;

我还是不明白为什么它不能按原来的方式工作。

最新更新