使用@EmbeddedId 在复合键上通过@GeneratedValue 生成NULL ID [英] NULL ID Generated Via @GeneratedValue On Composite Key Using @EmbeddedId

查看:31
本文介绍了使用@EmbeddedId 在复合键上通过@GeneratedValue 生成NULL ID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试通过 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 实际上是非nullrepository.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:

  1. 使用 @Version 注释字段并在第一次调用 save(…) 之前保持未初始化.
  2. 实现 Persistable 及其 isNew() 方法来检查您的对象状态以正确确定它是否是新的(在您的情况下可能通过检查 (pk.cashBatchIDnull).
  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).

这篇关于使用@EmbeddedId 在复合键上通过@GeneratedValue 生成NULL ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆