问题
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!
回答1:
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:
- Use an
@Version
annotated field and leave this uninitialized before the first call tosave(…)
. - Implement
Persistable
and itsisNew()
method to inspect your objects state to correctly decide whether it's new or not (in your case probably by checking (pk.cashBatchID
for beingnull
).
来源:https://stackoverflow.com/questions/24088776/null-id-generated-via-generatedvalue-on-composite-key-using-embeddedid