Search code examples
javahibernatejpatransactionshibernate-entitymanager

Persisting 2 table with the same generated id


I try to persist one parent entity which is joined with another child entity, but the problem is that the id is not generated for this child when persisting so I have this error : [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-01400: cannot insert NULL into ("L2S$OWNER"."SABRI"."TRANSITION_MATRIX_ID")

there is the child Entity :

@Data
@Entity
@IdClass(MyLibrarySabriEntityPK.class)
@Table(name = "SABRI", schema = "L2S$OWNER", catalog = "")

public class MyLibrarySabriEntity extends ActionForm {
@Access(AccessType.FIELD)
@Id
@ManyToOne
@JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;

@Id
private String RATING_ID_ROW;

@Id
private String RATING_ID_COL;


@Basic
@Column(name = "TRANSITION_PROBABILITY", nullable = true, insertable = true, updatable = true, precision = 20)
private Double TRANSITION_PROBABILITY;}

the PK class :

@Data
public class MyLibrarySabriEntityPK implements Serializable {
private String TRANSITION_MATRIX_ID;
private String RATING_ID_ROW;
private String RATING_ID_COL;


public MyLibrarySabriEntityPK(String TRANSITION_MATRIX_ID,String RATING_ID_COL,String RATING_ID_ROW ){
    this.TRANSITION_MATRIX_ID=TRANSITION_MATRIX_ID;
    this.RATING_ID_COL = RATING_ID_COL;
    this.RATING_ID_ROW= RATING_ID_ROW;
}

}

there is the parent Entity:

@Data
@Entity
@Table(name = "TEST", schema = "L2S$OWNER", catalog = "")
public class MyLibraryTestEntity extends ActionForm {

    @Access(AccessType.FIELD)
    @OneToMany(mappedBy = "sabriEntity", cascade = CascadeType.PERSIST)
    private final List<MyLibrarySabriEntity> entities = new ArrayList<MyLibrarySabriEntity>(25);

    public void addEntitysabri(MyLibrarySabriEntity entity) {
        getEntities().add(entity);
        entity.setSabriEntity(this);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "IdGenerated")
    @GenericGenerator(name = "IdGenerated", strategy = "dao.Identifier")
    @Column(name = "ID_TRANSITION_MATRIX", nullable = false, insertable = false, updatable = false, length = 10)
    private String ID_TRANSITION_MATRIX;


    @Basic
    @Column(name = "REFERENCE", nullable = true, insertable = true, updatable = true, precision = 0)
    private Integer reference;}

And here I try to persist the parent table which is supposed to persist also the child table but the Id is not generated !

MyLibrarySabriEntity Entity = null;
MyLibraryTestEntity test = getMyLibraryTestEntity(matrixStartDate, matrixName);  // here I get the values of my entity test (parent)
    try {
        transaction.begin();
        for (int row = 0; row < 20; row++) {
            for (int col = 0; col < 20; col++) {
                double val = cells.get(row + FIRST_ROW, col + FIRST_COL).getDoubleValue();
                Entity = getMyLibrarySabriEntity(col, row, val); // this get the values of the Entity parameters (child)
                Entity.setSabriEntity(test);
                test.addEntitysabri(Entity);
                em.persist(test);
            }
        }


    } catch (Exception e) {
        if (transaction.isActive())
            transaction.rollback();
        LOGGER.warn(e.getMessage(), e);

    } finally {
        if (transaction.isActive())
            transaction.commit();
        em.close();

    }

Solution

  • Assuming you are using JPA 2.0+

    Remove this mapping completely:

    @Id
    @Column(name = "TRANSITION_MATRIX_ID", nullable = false, 
           insertable = true, updatable = true, length = 100)
    private String TRANSITION_MATRIX_ID;
    

    and put the @Id directly on the ManyToOne and remove the insertable and updateable attributes.

    @Access(AccessType.FIELD)
    @Id
    @ManyToOne
    @JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
    private MyLibraryTestEntity sabriEntity;
    

    Update your ID class accordingly. Any previous reference to TRANSITION_MATRIX_ID should be replaced with a reference to sabriEntity. You are also confusing @EmbeddedId and @IdClass: Only the former would contain column definitions whereas you are using the latter approach.

    public class MyLibrarySabriEntityPK implements Serializable {
    
        private String sabriEntity;
        private String RATING_ID_ROW;
        private String RATING_ID_COL;
    }
    

    See:

    https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0