Cascade 持久化具有未知 PK/FK 属性的 JPA 实体违反了 NotNullConstraint

Cascade persist JPA entities with unknown PK/FK attributes violates NotNullConstraint

我想保留一个具有许多 1:1 或 1:many 关系的 JPA 实体,只调用一次 persist.

问题:实体的主键是自动生成的,并用作子实体的外键。提交事务时,出现异常,指出子实体的外键列上违反了 NotNullConstraint。

Internal Exception: java.sql.SQLException: ORA-01400: Insertion of NULL in ("SCHEMA"."PROTOCOL_FILE"."PROTOCOL_ID") not possible

父实体:

@Entity
@Table(name = "...")
public class Protocol {

    @Id
    @GeneratedValue(generator="SQ_PROTOCOL", strategy=GenerationType.SEQUENCE)
    @SequenceGenerator(name="SQ_PROTOCOL", sequenceName="SQ_PROTOCOL", allocationSize=50)
    @Column(name = "PROTOCOL_ID")
    private Long protocolId;

    @OneToOne(mappedBy="protocol", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private ProtocolFile file;

    //Other attributes and getter/setter omitted
}

子实体:

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id
    @Column(name = "PROTOCOL_ID")
    private Long protocolId;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumns(@JoinColumn(name="PROTOCOL_ID", referencedColumnName="PROTOCOL_ID", updatable=false, insertable=false))
    private Protocol protocol;

    //Other attributes and getter/setter omitted
}

你知道一个方便的解决方案吗,这样我就可以在一次调用中保留属于 Protocol 的所有实体?

你这里的情况是 ProtocolFile 的 "derived identity" - ProtocolFile 的 ID 是 Protocol 的 ID,并且有一个 -它们之间是一对一的关系。

我看到您正在使用 updatable=false, insertable=false,但最好遵循建议使用 @MapsId 注释的规范:

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id // No @Column here
    private Long protocolId;

    @MapsId // --- HERE
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="PROTOCOL_ID") // Just that
    private Protocol protocol;
}

或者您可能想完全跳过 protocolId 字段并在关系上添加 @Id 注释。

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id // --- HERE
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="PROTOCOL_ID") // Just that
    private Protocol protocol;
}

当然,您需要在创建时将 protocol 实例设置为 file,以后不要再更改它(例如,只允许使用 ProtocolFile 设置它构造函数)。

有关更多详细信息和示例,请参阅 JPA 2.0 spec 的“2.4.1 对应于派生身份的主键”部分(示例 4 似乎是您的情况)。