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

随声附和 提交于 2019-12-19 11:38:09

问题


I would like to persist a JPA entity with many 1:1 or 1:many relationships with only one call to persist.

Problem: the entity's primary key is auto generated and used as a foreign key in a child entity. When the transaction is committed, there is an exception pointing out a violated NotNullConstraint on the child entity's foreign key column.

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

Parent entity:

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

Child entity:

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

Do you know a convenient solution, so I can persist all entities, that belong to Protocol, in one call?


回答1:


The situation you have here is a "derived identity" of the ProtocolFile - the ID of the ProtocolFile is the ID of the Protocol and there is a one-to-one relationship between them.

I see you are using updatable=false, insertable=false but it's better to follow the specs which suggest to use the @MapsId annotation:

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

Or you may want to skip the protocolId field altogether and put the @Id annotation on the relationship.

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

Of course, you need to set the protocol instance to the file during creation and not change it later any more (eg. allow to set it only using the ProtocolFile constructor).

See section "2.4.1 Primary Keys Corresponding to Derived Identities" of the JPA 2.0 spec for more details and examples (Example 4 seems to be your case).



来源:https://stackoverflow.com/questions/32627062/cascade-persist-jpa-entities-with-unknown-pk-fk-attributes-violates-notnullconst

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!