使用@EmbeddedId 在复合键上通过@GeneratedValue 生成NULL ID [英] NULL ID Generated Via @GeneratedValue On Composite Key Using @EmbeddedId
问题描述
尝试通过 Spring Data JPA 在具有复合键(Long & Date)的表中保存一行.复合键的 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 类
@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
实例被传递时,pk
实际上是非null
到 repository.save(…)
.如果是这样,这将导致 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(...)
或 merge(…)
在 JPA 案例中).默认情况下,这通过查看 id 字段并将 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屋!