JPA 2.1 实体,为什么我总是得到实体自身而不是实体的主键?

JPA 2.1 entity, Why I always got the entity self instead of the entity's primary key?

这是对我之前问题的更深入挖掘。

我有一个由 Postgresql 服务器生成的 NetBeans 实体 classes。源代码是:

package com.longz.ozssc.domain;

import javax.persistence.*;
import java.sql.Time;
import java.util.Arrays;

/**
 * Created by cidylong on 12/01/2015.
*/
@Entity
@Table(name = "file", schema = "public", catalog = "ozssc")
public class FileEntity {
    private String fileId;
    private String referId;
    private String fileName;
    private String fileType;
    private byte[] fileData;
    private Time createdDatatime;

@Id
@Column(name = "file_id", nullable = false, insertable = true, updatable = true, length = 2147483647)
public String getFileId() {
    return fileId;
}

public void setFileId(String fileId) {
    this.fileId = fileId;
}

@Basic
@Column(name = "refer_id", nullable = false, insertable = true, updatable = true, length = 2147483647)
public String getReferId() {
    return referId;
}

public void setReferId(String referId) {
    this.referId = referId;
}

@Basic
@Column(name = "file_name", nullable = false, insertable = true, updatable = true, length = 2147483647)
public String getFileName() {
    return fileName;
}

public void setFileName(String fileName) {
    this.fileName = fileName;
}

@Basic
@Column(name = "file_type", nullable = true, insertable = true, updatable = true, length = 2147483647)
public String getFileType() {
    return fileType;
}

public void setFileType(String fileType) {
    this.fileType = fileType;
}

@Basic
@Column(name = "file_data", nullable = false, insertable = true, updatable = true)
public byte[] getFileData() {
    return fileData;
}

public void setFileData(byte[] fileData) {
    this.fileData = fileData;
}

@Basic
@Column(name = "created_datatime", nullable = false, insertable = true, updatable = true)
public Time getCreatedDatatime() {
    return createdDatatime;
}

public void setCreatedDatatime(Time createdDatatime) {
    this.createdDatatime = createdDatatime;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    FileEntity that = (FileEntity) o;

    if (createdDatatime != null ? !createdDatatime.equals(that.createdDatatime) : that.createdDatatime != null)
        return false;
    if (!Arrays.equals(fileData, that.fileData)) return false;
    if (fileId != null ? !fileId.equals(that.fileId) : that.fileId != null) return false;
    if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) return false;
    if (fileType != null ? !fileType.equals(that.fileType) : that.fileType != null) return false;
    if (referId != null ? !referId.equals(that.referId) : that.referId != null) return false;

    return true;
}

@Override
public int hashCode() {
    int result = fileId != null ? fileId.hashCode() : 0;
    result = 31 * result + (referId != null ? referId.hashCode() : 0);
    result = 31 * result + (fileName != null ? fileName.hashCode() : 0);
    result = 31 * result + (fileType != null ? fileType.hashCode() : 0);
    result = 31 * result + (fileData != null ? Arrays.hashCode(fileData) : 0);
    result = 31 * result + (createdDatatime != null ? createdDatatime.hashCode() : 0);
    return result;
}
@Override
public String toString() {
    return "com.longz.ozssc.model.FileEntity[ fileId=" + fileId + " ]";
}

}

这是我在项目中使用的非常流行的实体 class。实体主键是fileId,有一组getter/setter对访问实体中的私有属性,如setFileId(String fileId)和getFileId()。

我的远程接口是:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.longz.ozssc.remote;

import com.longz.ozssc.model.FileEntity;
import java.util.List;
import javax.ejb.Remote;

/**
 *
 * @author cidylong
*/
@Remote
public interface FileEntityFacadeRemote {

  void create(FileEntity fileEntity);

  void edit(FileEntity fileEntity);

  void remove(FileEntity fileEntity);

  FileEntity find(Object id);

  List<FileEntity> findAll();

  List<FileEntity> findRange(int[] range);

  int count();

}

我的 EJB 实现是:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.longz.ozssc.ejb;

import com.longz.ozssc.model.FileEntity;
import com.longz.ozssc.remote.FileEntityFacadeRemote;
import com.longz.ozssc.remote.OzsscIdSequenceFacadeRemote;
import com.longz.ozssc.utils.datatime.DateTimeAssistant;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author cidylong
 */
@Remote(FileEntityFacadeRemote.class)
@Stateless(mappedName="fileEntityFacadeEJB")
public class FileEntityFacade extends AbstractFacade<FileEntity> implements FileEntityFacadeRemote {
    @PersistenceContext(unitName = "OzsscJPANBPU")
    private EntityManager em;

  @Override
  protected EntityManager getEntityManager() {
    return em;
}

  public FileEntityFacade() {
    super(FileEntity.class);
}

  @EJB
  private OzsscIdSequenceFacadeRemote ozsscIdSqFaRemote;

  @Override
  public List<FileEntity> findAll(){
    Query query = em.createNamedQuery("FileEntity.findAllOrderByCreated");
    return new LinkedList<FileEntity>(query.getResultList());
    /*return super.findAll();*/
}

}

每次调用实体方法 getFileId() 时,

 String fileId = (FileEntity)fileEntity.getFileId();

假设我将从实体中得到一个字符串 return,例如:

**FILES20150200013**. 

但我的实体总是return:

**com.longz.ozssc.model.FileEntity[ fileId= FILES20150200013 ]**

这个return值正是其他实体方法toString()的打印出来的。也就是说,

当我调用 getFileId() 方法访问实体的主键时,实体 return 对我来说是一个完整的实体值,而不是 return 一个主键。

是我的代码有问题还是实体访问方法有问题?

欢迎任何建议,并非常感谢。

编辑:

当我尝试使用 JPA 2.0 提供的方法访问实体的主键时:

Object identifier = 
                EntityManagerFactory.getPersistenceUnitUtil().getIdentifier(fileEntity);

我也错了return。烦??

我自己发现了这个问题。

其实。我用 java 客户端包括 WebLogic 客户端库对其进行了测试,我发现它在 Java 客户端中运行良好。

然后,我将相同的测试代码放入 Spring MVC 上下文中,但没有用。 Spring MVC 控制器总是给出错误的 return 值。很好笑。

作为替代解决方案。我使用 Spring 表单对象通过使用 ABN 字符串而不是使用 FirmEntity 来重新组织参数,然后我将 ABN 字符串传递给 EJB,我得到了正确的 return.

这也许可以帮助遇到同样问题的其他人。我认为这个问题是由 Spring Frameworks 的 AOP 功能将错误的字符串绑定到 return 值引起的,在使用此类功能时应该非常小心。