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?
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).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.