Foreign Key in Child Entity Remains Null When Parent Uses Sequence Generator with Cascade SAVE_UPDATE

I’ve encountered an issue in a parent-child entity relationship while using Spring 6.2.2 and hibernate-core-jakarta 5.6.15.Final, Oracle Database where:

  • The parent entity has a primary key generated using a sequence.
  • The child entity has a composite key, which includes a foreign key reference to the parent.
  • The cascade type is SAVE_UPDATE on the parent-child relationship.

Issue Description

When saving the parent entity, Hibernate correctly triggers inserts for both the parent and child due to the cascade setting. However, the child entity’s foreign key remains null, causing an SQLIntegrityConstraintViolationException (ORA-01400: cannot insert NULL into (“SCHEMA_NAME”.“CHILD”.“ID”).

Expected Behavior

The parent’s primary key, generated via the sequence, should be set in the child entity’s foreign key (ID) before insertion.

Sample Code

@Entity
@Table(name = "`PARENT`")
public class Parent implements Serializable {

    @Id
    @SequenceGenerator(name = "generator", sequenceName = "`SAMPLE_SEQUENCE1`" , allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
    @Column(name = "`ID`", nullable = false, scale = 0, precision = 10)
    private Long id;

    @Column(name = "`NAME`", nullable = true, length = 20)
    private String name;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
    @Cascade({CascadeType.SAVE_UPDATE})
    private List<Child> children = new ArrayList<>();

    // Getters and setters

    @PostPersist
    private void onPostPersist() {
        if(children != null) {
            children.forEach(_child -> _child.setParent(this));
        }
    }
}
@Entity
@Table(name = "`CHILD`")
@IdClass(ChildIdClass.class)
public class Child implements Serializable {

    @Id
    @Column(name = "`CHILD_ID`", nullable = false, scale = 0, precision = 10)
    private Long childId;
    
    @Id
    @Column(name = "`ID`", nullable = false, scale = 0, precision = 10)
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "`ID`", referencedColumnName = "`ID`", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "`PC_FK`"))
    @Fetch(FetchMode.JOIN)
    private Parent parent;

    public void setParent(Parent parent) {
        if(parent != null) {
            this.id = parent.getId();
        }
        this.parent = parent;
    }

    // Getters and setters
}
public class ChildIdClass implements Serializable {

    private Long id;
    private Long childId;

    // Getters, setters, equals, and hashCode methods
}

Service Layer

In the service layer, the parent entity is saved as follows:

getHibernateTemplate().save(parentEntity);
getHibernateTemplate().flush();

Debug Logs & Observation

Debug logs show that when Hibernate saves the entities:

[org.hibernate.internal.util.EntityPrinter] - Listing entities:
[org.hibernate.internal.util.EntityPrinter] - com.orclcdb.Parent{id=362, name=abc, children=[com.orclcdb.Child]}
[org.hibernate.internal.util.EntityPrinter] - com.orclcdb.Child{parent=null}
[org.hibernate.SQL] - insert into "SCHEMA_NAME"."PARENT" ("ID", "NAME") values (?, ?)
[org.hibernate.SQL] - insert into "SCHEMA_NAME"."CHILD" ("CHILD_ID", "ID") values (?, ?)
[org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - could not execute statement [n/a]
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("SCHEMA_NAME"."CHILD"."ID")

Observation

  • The @PostPersist method in Parent is supposed to assign the generated ID to the Child entity.
  • However, @PostPersist is called only during flush(), not at the time of save() and during flush operation the id field in the ChildIdClass is already null so the data that is being inserted is null.

Additional Observations

This issue does not occur when:

  1. The parent uses IDENTITY generation instead of SEQUENCE.
  2. The parent has no generator, meaning the ID is manually assigned before persistence.

Please update to the latest Hibernate ORM version and also read Maintenance Policy - Hibernate to understand the need for that.