Hibernate - OneToMany ORA-02291 - 违反 - 找不到父键

Hibernate - OneToMany ORA-02291 - violated - parent key not found

我遇到错误:ORA-02291:完整性约束 - 违反 DESCRIPTOR__FK 从 JpaRepository

调用 .saveAll() 时未找到父键

我的数据库是 Oracle 18c

我在 FINDINGSDESCRIPTOR 下面有 2 个表格。 1 个调查结果记录可以有多个描述符

create table FINDINGS
(
    CLAIMNO VARCHAR2(50),
    TRACEID VARCHAR2(50),
    RULE VARCHAR2(10),
    NUMBEROFFINDINGS INT,
    constraint FINDINGS_PK
        primary key (CLAIMNO, TRACEID)
)
/

create table DESCRIPTOR
(
    TBL_ROW_ID int,
    CLAIMNO VARCHAR2(50) not null,
    TRACEID VARCHAR2(50) not null,
    DESCRIPTOR VARCHAR2(4000),
    constraint DESCRIPTOR_PK
        primary key (CLAIMNO, TBL_ROW_ID, TRACEID),
    constraint DESCRIPTOR__FK
        foreign key (CLAIMNO, TRACEID) references FINDINGS
)
/

我的实体代码:

@Getter
@Setter
public class FindingsDOPK implements Serializable {

    private static final long serialVersionUID = -7629886512750674550L;
    private String claimno;
    private String traceid;
}

@Getter
@Setter
public class DescriptorDOPK implements Serializable {

    private static final long serialVersionUID = 5528285828768013262L;
    private FindingsDO findingsDO;
    private int tblRowId;

}


@Entity
@Getter
@Setter
@Table(name = "DESCRIPTOR")
@IdClass(DescriptorDOPK.class)
public class DescriptorDO implements Serializable {

    private static final long serialVersionUID = 8951191961032280402L;

    @Id
    @Column(name = "TBL_ROW_ID")
    private int tblRowId;

    @Basic
    @Column(name = "DESCRIPTOR")
    private String descriptor;

    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST }, optional = false)
    @JoinColumns(
            value = { @JoinColumn(name = "TRACEID", referencedColumnName = "CLAIMNO", nullable = false),
                    @JoinColumn(name = "CLAIMNO", referencedColumnName = "TRACEID", nullable = false) })
    private FindingsDO findingsDO;

}



@Entity
@Setter
@Getter
@Table(name = "FINDINGS")
@IdClass(FindingsDOPK.class)
public class FindingsDO implements Serializable {

    private static final long serialVersionUID = -3271206505226648660L;
    @Id
    @Column(name = "CLAIMNO")
    private String claimno;
    @Id
    @Column(name = "TRACEID")
    private String traceid;
    @Basic
    @Column(name = "RULE")
    private String rule;

    @Basic
    @Column(name = "NUMBEROFFINDINGS")
    private int numberoffindings;

    @OneToMany(mappedBy = "findingsDO", fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
    private Set<DescriptorDO> descriptorDOS;

}

我的java代码:

 final List<FindingsDO> findingList = new ArrayList<>();
 final var findingsDO = new FindingsDO();
 findingsDO.setClaimno("123");
 findingsDO.setTraceid("2e22a7b2-d1bb-41ff-9465-3d21da2a31");
 findingsDO.setRule("RULE_123");
 findingsDO.setNumberoffindings(1);

 final Set<DescriptorDO> descriptorSet = new HashSet<>();
 final var descriptorDO = new DescriptorDO();
 descriptorDO.setTblRowId(1);
 descriptorDO.setDescriptor("descriptor_1");

 descriptorSet.add(descriptorDO);

 for (final DescriptorDO descriptorDO : descriptorSet) {
     descriptorDO.setFindingsDO(findingsDO);
 }

 findingsDO.setDescriptorDOS(descriptorSet);

 findingList.add(findingsDO);

 findingRepository.saveAll(findingList);

Hibernate 日志和按顺序生成的查询:

Hibernate: /* load FindingsDO */
select finding0_.TRACEID          as traceid1_8_1_,
       finding0_.CLAIMNO          as claimno2_8_1_,
       finding0_.NUMBEROFFINDINGS as numberoffindings3_8_1_,
       finding0_.RULE             as rule4_8_1_,
       descrip1_.CLAIMNO          as claimno3_7_3_,
       descrip1_.TRACEID          as traceid4_7_3_,
       descrip1_.TBL_ROW_ID       as tbl_row_id1_7_3_,
       descrip1_.TBL_ROW_ID       as tbl_row_id1_7_0_,
       descrip1_.CLAIMNO          as claimno3_7_0_,
       descrip1_.TRACEID          as traceid4_7_0_,
       descrip1_.DESCRIPTOR       as descriptor2_7_0_
from FINDINGS finding0_
         left outer join DESCRIPTOR descrip1_
                         on finding0_.TRACEID = descrip1_.CLAIMNO and finding0_.CLAIMNO = descrip1_.TRACEID
where finding0_.TRACEID = ?
  and finding0_.CLAIMNO = ?

Hibernate: /* load DescriptorDO */
select descrip0_.TBL_ROW_ID       as tbl_row_id1_7_1_,
       descrip0_.CLAIMNO          as claimno3_7_1_,
       descrip0_.TRACEID          as traceid4_7_1_,
       descrip0_.DESCRIPTOR       as descriptor2_7_1_,
       finding1_.TRACEID          as traceid1_8_0_,
       finding1_.CLAIMNO          as claimno2_8_0_,
       finding1_.NUMBEROFFINDINGS as numberoffindings3_8_0_,
       finding1_.RULE             as rule4_8_0_
from DESCRIPTOR descrip0_
         inner join FINDINGS finding1_
                    on descrip0_.CLAIMNO = finding1_.TRACEID and descrip0_.TRACEID = finding1_.CLAIMNO
where descrip0_.TBL_ROW_ID = ?
  and descrip0_.CLAIMNO = ?
  and descrip0_.TRACEID = ?

Hibernate: /* insert FindingsDO */
insert into FINDINGS (NUMBEROFFINDINGS, RULE, TRACEID, CLAIMNO) values (?, ?, ?, ?)

Hibernate: /* insert DescriptorDO */
insert into DESCRIPTOR (DESCRIPTOR, TBL_ROW_ID, CLAIMNO, TRACEID) values (?, ?, ?, ?)

我该如何解决这个问题?

我通过将 CascadeType 更改为 CascadeType.ALL

来解决此问题

调查结果DO:

@OneToMany(mappedBy = "findingsDO", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<DescriptorDO> descriptorDOS;

描述符DO:

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumns(
        value = { @JoinColumn(name = "TRACEID", referencedColumnName = "TRACEID", nullable = false),
                @JoinColumn(name = "CLAIMNO", referencedColumnName = "CLAIMNO", nullable = false) })
private FindingsDO findingsDO;

我不确定背后的原因是什么,但我刚刚阅读了这篇文章,然后尝试使用 ALL 并且有效 https://www.baeldung.com/jpa-cascade-types