Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NULL ID Generated Via @GeneratedValue On Composite Key Using @EmbeddedId

Trying to save a row in a table that has a composite key (Long & Date) via Spring Data JPA. The Long part of the composite key is @GeneratedValue. But I'm getting the following error when doing a basic save() call:

org.hibernate.id.IdentifierGenerationException: null id generated for:class com.bts.billing.domain.CashBatchPaymentHistoryDto

The date is getting set manually prior to the save() and I've validated the sequencer exists in the database and is accessible.

Entity

@Entity
@Table(name = "CASH_BATCH_PMT_H")
public class CashBatchPaymentHistoryDto implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private CashBatchPaymentHistoryPK pk;

    private Date        cashBatchProcDt;
    @Column(name = "C_CBP_STS", nullable = false)
    private String      cashBatchStatus;
    @Column(name = "C_CBP_TYP", nullable = false)
    private String      cashBatchType;

    //Removed Getters & Setters To Save Space
}

@Embeddable Class

@Embeddable    
@SequenceGenerator(name = "CBPMT", sequenceName = "CBPMT", allocationSize = 1)
public class CashBatchPaymentHistoryPK implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(name = "N_CBP_OID", nullable=false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CBPMT")
    private Long cashBatchID;
    @Column(name = "D_CBP_PROC", nullable=false)
    private Date cashBatchProcDt;

    public CashBatchPaymentHistoryPK() {}

    public CashBatchPaymentHistoryPK(long cashBatchID, Date cashBatchProcDt) {
        this.cashBatchID = cashBatchID;
        this.cashBatchProcDt = cashBatchProcDt;
    }

    //Removed Getters & Setters For Space

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (cashBatchID ^ (cashBatchID >>> 32));
        result = prime * result + (int) (cashBatchProcDt.hashCode() ^ (cashBatchProcDt.hashCode() >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        CashBatchPaymentHistoryPK other = (CashBatchPaymentHistoryPK) obj;
        if (cashBatchID != other.cashBatchID) {
            return false;
        }
        if (cashBatchProcDt != other.cashBatchProcDt) {
            return false;
        }
        return true;
    }
}

Repository Class

public interface CashBatchPaymentHistoryRepository extends CrudRepository<CashBatchPaymentHistoryDto, CashBatchPaymentHistoryPK> {
}

Any thoughts on the issue? Thanks!

like image 763
Brandon Oakley Avatar asked Jun 06 '14 18:06

Brandon Oakley


1 Answers

It looks like you're setting the ID value to half-prepared state (Date being set but the long field to be initialized by the persistence provider, right? This means, pk is effectively non-null when the CashBatchPaymentHistoryDto instance is handed to repository.save(…). If so, this will cause an EntityManager.merge(…) being triggered, which can imagine to cause the exception as it's not going to expect to have to generate ids.

Generally speaking, if you're manually maintaining id values (even only partial ones), you have to explicitly determine the is-new-state of the entity (as this will effectively decide whether to call persist(…) or merge(…) in the JPA case). By default, this works by looking at the id field and interpreting a null value as new, non-null as not new.

In your current situation there are two options:

  1. Use an @Version annotated field and leave this uninitialized before the first call to save(…).
  2. Implement Persistable and its isNew() method to inspect your objects state to correctly decide whether it's new or not (in your case probably by checking (pk.cashBatchID for being null).
like image 100
Oliver Drotbohm Avatar answered Sep 17 '22 08:09

Oliver Drotbohm