# Persist parent and child - With data integrity

**URL:** <https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023>\
**Category:** Hibernate ORM\
**Created:** [February 13, 2024, 3:18pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023 "2024-02-13T15:18:45Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tom123](https://avatars.discourse-cdn.com/v4/letter/t/d78d45/32.png) [@Tom123](https://discourse.hibernate.org/u/Tom123)\
**Post date:** [February 13, 2024, 3:18pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/1 "2024-02-13T15:18:45Z")

</div>

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](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one-bidirectional)

Extract below:

> **Summary**
>
> ```auto
> @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
> 
> }
> 
> ```
> 
> ```auto
> 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:

```auto
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!)

---

<div class="post-metadata">

**Author:** ![mbladel](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/mbladel/32/2128_2.png) [@mbladel](https://discourse.hibernate.org/u/mbladel)\
**Post date:** [February 13, 2024, 3:29pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/2 "2024-02-13T15:29:50Z")

</div>

You are mapping two distinct entities, `Phone` and `PhoneDetails`, each of which has an `@Id private Long id` property - that’s why you are seeing distinct `id` columns. You are then defining a bidirectional `@OneToOne` association, where `PhoneDetails` is the owning side and `Phone` is the indirect side (`mappedBy`).

If you wish to use the associated `Phone`’s id as an identifier for `PhoneDetails`, you should simply drop the `Long id` column and just annotate the to-one association with `@Id`. Please also take a look at the [`@MapsId`](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#identifiers-derived) annotation and at Hibernate’s [inheritance capabilities](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance), which might be best suited depending on what you’re trying to achieve.

---

<div class="post-metadata">

**Author:** ![Tom123](https://avatars.discourse-cdn.com/v4/letter/t/d78d45/32.png) [@Tom123](https://discourse.hibernate.org/u/Tom123)\
**Post date:** [February 13, 2024, 3:58pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/3 "2024-02-13T15:58:24Z")

</div>

Thank you for the fast reply!

I don’t think inheritance is right for what I’m after. And I think @MapsId requires me to be in the Hibernate context to manage the IDs for me.

I think an example of what I’m trying to do might make more sense. I have the following tables:

> **DDL**
>
> ```auto
> create table companies
> (
> id int auto_increment primary key,
> name varchar(255) null
> );
> 
> create table company_details
> (
> company_id int not null,
> website varchar(500) null,
> constraint company_details_companies_id_fk
> foreign key (company_id) references companies (id)
> on delete cascade
> );
> 
> ```

Mapped to:

> **Entities**
>
> ```auto
> @Entity
> @Table(name = "companies")
> public class Company {
> 
> @Id
> @GeneratedValue(strategy = GenerationType.IDENTITY)
> @Column(name = "id")
> public int id;
> 
> @Column(name = "name")
> public String name;
> 
> @OneToOne(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
> public CompanyDetails details;
> 
> }
> 
> @Entity
> @Table(name = "company_details")
> public class CompanyDetails {
> 
> @Id
> @Column(name = "company_id")
> public int companyId;
> 
> @OneToOne(fetch = FetchType.LAZY)
> @JoinColumn(name = "company_id")
> private Company company;
> 
> @Column(name = "website", length = 500)
> public String website;
> 
> }
> 
> ```

I am then:

> **JSON to Java**
>
> Take a new Company from JSON:
> 
> ```auto
> {"name":"f", "details": {"website": "test"}}
> 
> ```
> 
> Run it through Jackson and persist it:  
> ![Screenshot from 2024-02-13 15-51-25](https://canada1.discourse-cdn.com/flex035/uploads/hibernate/original/2X/9/9f9bba27f97f896d816a2ee2c55e136c12179662.png)

And I get the following:

> **Log**
>
> ```auto
> 2024-02-13 15:53:13.393 | DEBUG | org.hibernate.SQL | dev : insert into companies (name) values (?)
> 2024-02-13 15:53:13.398 | TRACE | org.hibernate.orm.jdbc.bind | dev : binding parameter (1:VARCHAR) <- [f]
> 2024-02-13 15:53:14.434 | DEBUG | org.hibernate.SQL | dev : insert into company_details (website,company_id) values (?,?)
> 2024-02-13 15:53:14.440 | TRACE | org.hibernate.orm.jdbc.bind | dev : binding parameter (1:VARCHAR) <- [test]
> 2024-02-13 15:53:14.442 | TRACE | org.hibernate.orm.jdbc.bind | dev : binding parameter (2:INTEGER) <- [0]
> 2024-02-13 15:53:14.449 | WARN | o.h.engine.jdbc.spi.SqlExceptionHelper | dev : SQL Error: 1452, SQLState: 23000
> 2024-02-13 15:53:14.450 | ERROR | o.h.engine.jdbc.spi.SqlExceptionHelper | dev : Cannot add or update a child row: a foreign key constraint fails (`testDb`.`company_details`, CONSTRAINT `company_details_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE)
> 2024-02-13 15:53:29.866 | ERROR | testDb.Functions.CompanyFunctions | dev : Error while committing the transaction
> jakarta.persistence.RollbackException: Error while committing the transaction
> at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:67)
> at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
> ...
> Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [Cannot add or update a child row: a foreign key constraint fails (`testDb`.`company_details`, CONSTRAINT `company_details_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE)] [insert into company_details (website,company_id) values (?,?)]
> at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:62)
> at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:58)
> at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
> at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
> at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:107)
> at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:40)
> at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:52)
> at org.hibernate.persister.entity.mutation.InsertCoordinator.doStaticInserts(InsertCoordinator.java:175)
> at org.hibernate.persister.entity.mutation.InsertCoordinator.coordinateInsert(InsertCoordinator.java:113)
> at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2873)
> at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
> at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:632)
> at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:499)
> at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:363)
> at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:41)
> at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
> at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1423)
> at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:504)
> at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2339)
> at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1996)
> at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
> at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:169)
> at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:267)
> at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
> ... 101 common frames omitted
> Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`testDb`.`company_details`, CONSTRAINT `company_details_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE)
> at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:118)
> at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
> at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)
> at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1061)
> at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1009)
> at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1320)
> at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:994)
> at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:137)
> at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:137)
> at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:194)
> ... 121 common frames omitted
> 
> ```

Have I just misinterpreted what I should be doing? I’m aware this might not be the 100% the intended use of Hibernate - most examples show the Java objects being created and manipulated in Java within an entity manager context. But I feel like I’m just missing one tiny annotation I haven’t seen yet!

Thank you 🙂

---

<div class="post-metadata">

**Author:** ![Tom123](https://avatars.discourse-cdn.com/v4/letter/t/d78d45/32.png) [@Tom123](https://discourse.hibernate.org/u/Tom123)\
**Post date:** [February 13, 2024, 4:04pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/4 "2024-02-13T16:04:56Z")

</div>

Thank you for the fast reply. My reply got hidden by the spam filter! Hopefully will be unlocked soon.

---

<div class="post-metadata">

**Author:** ![Tom123](https://avatars.discourse-cdn.com/v4/letter/t/d78d45/32.png) [@Tom123](https://discourse.hibernate.org/u/Tom123)\
**Post date:** [February 14, 2024, 11:27am UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/5 "2024-02-14T11:27:20Z")

</div>

I’ve had my reply unhidden now 🙂

---

<div class="post-metadata">

**Author:** ![mbladel](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/mbladel/32/2128_2.png) [@mbladel](https://discourse.hibernate.org/u/mbladel)\
**Post date:** [February 14, 2024, 11:41am UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/6 "2024-02-14T11:41:08Z")

</div>

This is what’s happening:

- `Company` gets persisted, it has a `@GeneratedId` identifier so when inserting the row in the database a new value is assigned to its `id` column
- then, `CompanyDetails` gets cascade-persisted since it’s mapped as `@OneToOne(mappedBy = "company", cascade = CascadeType.ALL, [...])`, and it as `0` as `companyId`
- when the insert is executed on the datase, the `id` column of the `companies` table has another value, so you get a constraint violation error.

If you want the `Company` foreign key as the identifier for `CompanyDetails` you should just use `@MapsId` or remove the `companyId` property and simply annotate the association with `@Id`. Otherwise, you will have to manually assign the `Company` identifier **after** persisting the entity in the `CompanyDetails#companyId` property, so you won’t be able to use cascade-persist.

---

<div class="post-metadata">

**Author:** ![Tom123](https://avatars.discourse-cdn.com/v4/letter/t/d78d45/32.png) [@Tom123](https://discourse.hibernate.org/u/Tom123)\
**Post date:** [February 15, 2024, 4:11pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/7 "2024-02-15T16:11:42Z")

</div>

Thank you for the info!

Got it working using `@MapsId` and the `@JsonManagedReference` and `@JsonBackReference` annotations from Jackson.

Cheers.

---

<div class="post-metadata">

**Author:** ![ushhaha](https://avatars.discourse-cdn.com/v4/letter/u/f1d935/32.png) [@ushhaha](https://discourse.hibernate.org/u/ushhaha)\
**Post date:** [November 8, 2024, 6:26pm UTC](https://discourse.hibernate.org/t/persist-parent-and-child-with-data-integrity/9023/8 "2024-11-08T18:26:48Z")

</div>

Hi @Tom123 Can you please post your solution to understand better. I am unable to save the data in the child table.
