OpenJPA - 实例的 id 字段在查询时返回 null

Posted

技术标签:

【中文标题】OpenJPA - 实例的 id 字段在查询时返回 null【英文标题】:OpenJPA - id field of an instance is returning null on query 【发布时间】:2012-04-29 11:09:09 【问题描述】:

我正在使用 Apache CXF(2.5.2 版)来实现 REST 服务,这些服务可以在数据库表上添加、更新、删除、查询单个记录和记录列表。我在持久层中使用 OpenJPA(版本 2.2.0)。

例如,我有一个名为 Complaint 的表,映射到同名的实体类。投诉实体与此类似:

import java.io.Serializable;
import java.sql.Timestamp;  

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table; 



/**
 * The persistent class for the "Complaint" database table.
 * 
 */
@Entity
@Table(name = "Complaint")
@NamedQueries(
        @NamedQuery(name = "cmplById", query = "SELECT c FROM Complaint c WHERE c.id = ?1"),
        @NamedQuery(name = "cmplBySearchCriteria", query = "SELECT c FROM Complaint c WHERE  c.status = ?1 AND c.category = ?2 AND c.location = ?3 AND "
                + "c.reportDate BETWEEN ?4 AND ?5 ORDER BY c.id DESC")

)

public class Complaint implements Serializable 
    private static final long serialVersionUID = 1L;

    private Integer id;

    private String description;

    private String location;

    private Timestamp reportDate;

    private String reportedBy;

    private String status;

    private String category;

    public Complaint() 
    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id", nullable = false)
    public Integer getId() 
        return this.id;
    

    public void setId(Integer id) 
        this.id = id;
    

    @Column(name = "Description")
    public String getDescription() 
        return this.description;
    

    public void setDescription(String description) 
        this.description = description;
    

    @Column(name = "Location")
    public String getLocation() 
        return this.location;
    

    public void setLocation(String location) 
        this.location = location;
    

    @Column(name = "ReportDate", nullable = false)
    public Timestamp getReportDate() 
        return this.reportDate;
    

    public void setReportDate(Timestamp reportDate) 
        this.reportDate = reportDate;
    

    @Column(name = "ReportedBy", nullable = false)
    public String getReportedBy() 
        return this.reportedBy;
    

    public void setReportedBy(String reportedBy) 
        this.reportedBy = reportedBy;
    

    @Column(name = "Status", nullable = false)
    public String getStatus() 
        return this.status;
    

    public void setStatus(String status) 
        this.status = status;
    

    @Column(name = "Category", nullable = false)
    public String getCategory() 
        return category;
    

    public void setCategory(String category) 
        this.category = category;
    


所有服务都运行良好,除了与返回数据的两个查询操作相关的问题。

getComplaintByIdgetAllComplaint 操作当前返回具有数据库中所有可用值的字段的实体,但 id 字段返回为空强>。我尝试以三种方式构造这些方法中的查询——使用命名查询、使用本机 sql 和使用实体管理器上的 find 方法——所有这些都给出了相同的结果。

只是为了测试,如果我尝试基于空检查设置 id 字段的值,它不允许我说 id 字段具有最终值。

我发现针对 mysql 和 Postgres 数据库运行代码的结果相同。这是其中一种查询方法的代码。

public Complaint getComplaintById(Integer id)      
        Complaint cmpl;

    //case-1: The NamedQueries as defined in the entity class Complaint --> @NamedQuery(name="cmplById", query="SELECT c FROM Complaint c WHERE c.id = ?1")
    //Query query = em.createNamedQuery("cmplById");

    //case-2: using NativeQuery
    //Query query = em.createNativeQuery("SELECT * FROM COMPLAINT WHERE ID=?1", Complaint.class);

    //query.setParameter(1, id);
    //cmpl = (Complaint) query.getSingleResult();  

    //case-3: using find method on entity manager        
    cmpl = em.find(Complaint.class, id);

    System.out.println("id = " + cmpl.getId());//returning null, but get method on all other fields returning their values as expected. 

    return cmpl; 

在日志中,我看到 OpenJPA 正在执行的查询语句包括所有其他字段,但不包括 select 子句中的 id 字段,如下所示。

1720 ramsjpa TRACE ["http-bio-8080"-exec-3] openjpa.jdbc.SQL - 执行 prepstmnt 14227847 SELECT t0.Category, t0.Description, t0.Location, t0.ReportDate, t0.ReportedBy, t0 .Status 来自投诉 t0 WHERE t0.Id = ? [参数=?]

我是第一次使用 CXF 和 OpenJPA,我可能会犯一个基本错误,感谢所有帮助。

【问题讨论】:

您没有包含实体类的实际来源。请将其添加到您的问题中。如果这个实体中的id 字段被标记为最终?编辑代码时不要忘记包含getId() 的定义。 @Perception,感谢您的快速回复,我已经添加了实体类,id字段没有标记为final。 你如何增强你的实体? 【参考方案1】:

您是否可能在将 getComplaintById 插入数据库后立即调用它?如果是这样,那么您的问题可能与将 GenerationType.IDENTITY 用于您的 Id 字段有关。使用 GenerationType.IDENTITY,由于在插入行之前数据库不会分配 id,因此直到提交或刷新调用之后才能在对象中获取 id。 (参考:http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Identity_sequencing)

因此,我认为您需要在尝试按 ID 查找投诉之前执行以下操作:

Complaint complaint = new Complaint();
// Fill in your complaint fields...
em.persist(complaint);
em.flush();
em.getTransaction().commit();

【讨论】:

以上是关于OpenJPA - 实例的 id 字段在查询时返回 null的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenJPA 中使用 inet postgres 数据类型

使用 openJPA 持久化更新查询

如何查询具有相同字段的两个表,仅当字段值相同时才返回id

solr入门之Solr函数查询初使用之查询字段是否包含指定内容

OpenJPA/MySQL:在 where 子句中使用同一张表时修改表

OpenJPA:JPQL 与本机查询