使用@EmbeddedId通过复合键上的@GeneratedValue生成的NULL ID [英] NULL ID Generated Via @GeneratedValue On Composite Key Using @EmbeddedId
问题描述
尝试通过Spring Data JPA将行保存在具有复合键(长和日期)的表中.复合键的Long部分是@GeneratedValue.但是在进行基本的 save()调用时出现以下错误:
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
日期是在 save()之前手动设置的,我已经验证了音序器存在于数据库中并且可以访问.
The date is getting set manually prior to the save() and I've validated the sequencer exists in the database and is accessible.
@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
@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;
}
}
存储库类
public interface CashBatchPaymentHistoryRepository extends CrudRepository<CashBatchPaymentHistoryDto, CashBatchPaymentHistoryPK> {
}
对此问题有何想法?谢谢!
Any thoughts on the issue? Thanks!
推荐答案
您似乎将ID值设置为半准备状态(已设置Date
,但long
字段将由持久性初始化提供者,对吗?这意味着,当CashBatchPaymentHistoryDto
实例被移交给repository.save(…)
时,pk
实际上不是null
,如果是这样,这将导致触发EntityManager.merge(…)
,这可以想象会导致异常因为它不会期望必须生成ID.
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.
通常来说,如果您要手动维护id值(甚至只是部分值),则必须显式确定实体的is-new-state(因为这将有效地决定是调用persist(…)
还是null
值解释为新值,将非null
解释为非新值来实现.
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:
- 使用带
@Version
注释的字段,并在首次调用save(…)
之前保留未初始化的字段. - 实施
Persistable
及其isNew()
方法来检查对象状态,以正确地确定对象是否为新对象(在您的情况下,可能是通过检查(pk.cashBatchID
是否为null
)).
- 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
).
这篇关于使用@EmbeddedId通过复合键上的@GeneratedValue生成的NULL ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!