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

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

问题描述

尝试通过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(…)还是在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.cashBatchID是否为null)).
  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天全站免登陆