hibernate Spring Data JPA:无法在MySQL中使用带有外键的ON DELETE CASCADE删除OneToOne关系中的子记录

tquggr8v  于 2023-04-06  发布在  Spring
关注(0)|答案(1)|浏览(180)

我正在使用Spring Data JPA来Map应用程序中两个实体之间的OneToOne关系。实体是DM和DM_DATA,其中每个DM记录都有一个对应的DM_DATA记录。
DM表具有到DM_DATA表的外键约束,使用DM_DATA_ID列Map到DMD_DATA_ID(DM_DATA中的主键)。在JPA实体中使用DM实体上的@OneToOne和@JoinColumn注解以及DM_DATA实体上的@OneToOne(mappedBy =“dmData”)注解来定义关系。
我还将CASCADE选项添加到DM实体中的@OneToOne注解中,以启用级联删除。

父级:

@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中的delete语句删除DM记录时,DM_DATA记录不会被删除
我尝试使用DMD_DATA_ID列将外键约束添加到DM_DATA表,但这并没有解决问题。我还尝试切换外键关系的方向,但这导致插入新记录时出现不同的错误。
有没有办法在JPA中正确配置OneToOne关系,并在SQL脚本中镜像它,以启用子实体的级联删除?

u5i3ibmn

u5i3ibmn1#

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

父级:

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

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

相关问题