有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我想用一个对persist的调用来持久化一个具有多个1:1或1:多关系的JPA实体

问题:实体的主键自动生成,并用作子实体中的外键。提交事务时,会出现一个异常,指出子实体的外键列上违反了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的所有实体


共 (1) 个答案

  1. # 1 楼答案

    这里的情况是ProtocolFile的“派生身份”——这个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似乎就是您的情况)