I have noticed it’s not easy to persist a parent with a child at the same time if you want to maintain data integrity at the DB level. In this case, I would like the child’s parent ID to be not null with a foreign key.
This appears to not be possible because Hibernate persists the parent successfully, then the child without updating the child’s parent ID property. This leaves the insert statement for the child with an invalid value for parent ID. I am confused as to why the parent ID isn’t updated automatically; perhaps there is a config option I haven’t found…
Hibernate’s docs seems to suggest this behaviour is intended/known:
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional
Extract below:
Summary
@Entity(name = "Phone")
public static class Phone {
@Id
@GeneratedValue
private Long id;
@Column(name = "`number`")
private String number;
@OneToOne(
mappedBy = "phone",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PhoneDetails details;
//Getters and setters are omitted for brevity
public void addDetails(PhoneDetails details) {
details.setPhone(this);
this.details = details;
}
public void removeDetails() {
if (details != null) {
details.setPhone(null);
this.details = null;
}
}
}
@Entity(name = "PhoneDetails")
public static class PhoneDetails {
@Id
@GeneratedValue
private Long id;
private String provider;
private String technology;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "phone_id")
private Phone phone;
//Getters and setters are omitted for brevity
}
CREATE TABLE Phone (
id BIGINT NOT NULL ,
number VARCHAR(255) ,
PRIMARY KEY ( id )
)
CREATE TABLE PhoneDetails (
id BIGINT NOT NULL ,
provider VARCHAR(255) ,
technology VARCHAR(255) ,
phone_id BIGINT ,
PRIMARY KEY ( id )
)
ALTER TABLE PhoneDetails
ADD CONSTRAINT FKeotuev8ja8v0sdh29dynqj05p
FOREIGN KEY (phone_id) REFERENCES Phone
Why does PhoneDetails need its own ID column? This leaves the possibility to end up with a PhoneDetails row without a valid Phone to link to. Why not just have:
phone_id BIGINT NOT NULL
This would link PhoneDetails more tightly to Phone and ensure data is always valid.
Note in my case I am persisting my parent with children in one go, the object comes into my API from JSON so it is impractical to persist the children one by one for every entity/endpoint (and this is surely what Hibernate should be doing for the user!)
Is there some logic to this I’m missing or is it just impossible due to a constraint I’m not aware of? (If so, it would be great to add it to the docs!)