在工作单元克隆中遇到JPA Null或零主键 [英] JPA Null or zero primary key encountered in unit of work clone

查看:215
本文介绍了在工作单元克隆中遇到JPA Null或零主键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解 JPA 并负责制作数据库并为其插入一些值。我想知道如何找出最近插入的对象的ID是什么,所以我找到了一种方法,我需要使用 flush 的方法EntityManager

I learn about JPA and had task to make database and insert some values to it. I wondered how I can find out what was the ID of recently inserted object, so I found a way that I need to use flush method of EntityManager.

不幸的是我得到了


Null或者工作单元中遇到零主键克隆

Null or zero primary key encountered in unit of work clone

当我使用上述方法时异常。我认为问题在于我的数据库在自动增量上设置了所有 ID 我使用ORACLE 11G Express ),因此在提交之前它已经 null value并回滚事务。

exception when I use the above method. I think the problem lies in that my database has all ID's set on autoincrement ( I use ORACLE 11G Express ), so before commiting it has null value and it rollbacks transaction.

我可以做些什么来修复它?

这是DB(ID的是自动增量[oracle中的序列和触发器]):

This is DB ( ID's are autoincrement[Sequences and Triggers in oracle]):

public class Client {    
    public static void main(String[] args) {
        EntityManagerFactory emf =
                Persistence.createEntityManagerFactory("JpaIntroductionPU");        
        EntityManager em = emf.createEntityManager();
        EntityTransaction et = em.getTransaction();

        et.begin();

        Address ad1 = new Address();
        ad1.setStreet("Skaraktki");
        ad1.setCode("64-340");

        em.persist(ad1);
        em.flush();

        System.out.println(ad1.getAId());
        et.commit();
    }   
}




地址class



@Entity
@Table(name = "ADDRESS")
@NamedQueries({
    @NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a"),
    @NamedQuery(name = "Address.findByAId", query = "SELECT a FROM Address a WHERE a.aId = :aId"),
    @NamedQuery(name = "Address.findByStreet", query = "SELECT a FROM Address a WHERE a.street = :street"),
    @NamedQuery(name = "Address.findByCode", query = "SELECT a FROM Address a WHERE a.code = :code")})
public class Address implements Serializable {
    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id
    @Basic(optional = false)
    @Column(name = "A_ID")
    private BigDecimal aId;

    @Basic(optional = false)
    @Column(name = "STREET")
    private String street;

    @Basic(optional = false)
    @Column(name = "CODE")
    private String code;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "aId")
    private Employee employee;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "aId")
    private Department department;

    public Address() {
    }

    public Address(BigDecimal aId) {
        this.aId = aId;
    }

    public Address(BigDecimal aId, String street, String code) {
        this.aId = aId;
        this.street = street;
        this.code = code;
    }

    public BigDecimal getAId() {
        return aId;
    }

    public void setAId(BigDecimal aId) {
        this.aId = aId;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }       

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (aId != null ? aId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Address)) {
            return false;
        }
        Address other = (Address) object;
        if ((this.aId == null && other.aId != null) || (this.aId != null && !this.aId.equals(other.aId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "jpaintroduction.Address[ aId=" + aId + " ]";
    }

}


推荐答案

您需要使用 @GeneratedValue <注释您的ID字段,以便JPA知道数据库将自动生成id:

You need to annotate your id field with @GeneratedValue, in order for JPA to know that the DB will generate the id automatically:

@Id
@Basic(optional = false)
@Column(name = "A_ID")
@SequenceGenerator( name = "mySeq", sequenceName = "MY_SEQ", allocationSize = 1, initialValue = 1 )
@GeneratedValue(strategy=GenerationType.IDENTITY, generator="mySeq")
private BigDecimal aId;

使用oracle,您可以使用 GenerationType.IDENTITY @SequenceGenerator 在这种情况下,您不需要触发器来查询序列并填充ID,JPA将为您完成。我不确定 GenerationType.AUTO 是否可以使用oracle,但如果确实如此,你需要一个触发器来查询序列并填充id。 GenerationType.TABLE 是最便携的解决方案,因为您使用由JPA管理的独立表来存储序列,它适用于所有数据库。

With oracle you can use GenerationType.IDENTITY and @SequenceGenerator in which case you don't need a trigger to query the sequence and populate the ID, JPA will do it for you. I'm not sure if GenerationType.AUTO will work with oracle but if it does, you'd need a trigger to query the sequence and populate the id. GenerationType.TABLE is the most portable solution, since you use an independent table managed by JPA to store the sequence, it works across all databases.

检查上面链接中的文档。

Check the docs in the link above.

这篇关于在工作单元克隆中遇到JPA Null或零主键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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