Java JPA 在工作单元克隆中遇到空或零主键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22026715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:08:22  来源:igfitidea点击:

JPA Null or zero primary key encountered in unit of work clone

javasqloraclejakarta-eejpa

提问by ashur

I learn about JPAand 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 flushmethod of EntityManager.

我了解JPA并完成了制作数据库并向其插入一些值的任务。我不知道我怎么能发现什么是最近插入的对象的ID,所以我找到了一种方法,我需要使用flush的方法EntityManager

Unfortunately I got the

不幸的是我得到了

Null or zero primary key encountered in unit of work clone

在工作单元克隆中遇到空或零主键

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

当我使用上述方法时异常。我认为问题在于我的数据库都ID's设置为自动增量(我使用 ORACLE 11G Express),所以在提交它之前它null有价值并且它回滚事务。

What I can do to fix it ?

我能做些什么来解决它?

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

这是 DB(ID 是自动递增的 [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();
    }   
}

Address 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 + " ]";
    }

}

采纳答案by Camilo

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

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

@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;

With oracle you can use GenerationType.IDENTITYand @SequenceGeneratorin 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.AUTOwill work with oracle but if it does, you'd need a trigger to query the sequence and populate the id. GenerationType.TABLEis the most portable solution, since you use an independent table managed by JPA to store the sequence, it works across all databases.

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

Check the docs in the link above.

检查上面链接中的文档。

回答by kdoteu

This happend to me because I manually added an entry to my database with the id 0 (zero). In my case EclipseLink "couldn't" handle an id with zero. So I added following to my persistence.xml:

这发生在我身上,因为我手动将一个条目添加到我的数据库中,id 为 0(零)。在我的情况下,EclipseLink“无法”处理一个 id 为零。所以我在我的persistence.xml中添加了以下内容:

     <property name="eclipselink.allow-zero-id" value="true"/>

This property says EclipseLink to handle zero as a valid id.

此属性表示 EclipseLink 将零作为有效 ID 处理。

[1] http://meetrohan.blogspot.de/2011/11/eclipselink-null-primary-key.html

[1] http://meetrohan.blogspot.de/2011/11/eclipselink-null-primary-key.html