【问题标题】:Data type for UUID as a primary key in a JPA entity classUUID 的数据类型作为 JPA 实体类中的主键
【发布时间】:2012-10-10 07:49:04
【问题描述】:

我需要使用 JPA 对 DB2 数据库中的表读取和写入记录,其中主键是 UUID,存储在定义为“char(16) bit for data”的列中。

由于数据以位格式存储在数据库中,我无法将列视为 JPA 实体类中的字符串。经过一番谷歌搜索后,我在JPA and UUID primary keys 上找到了这个网页,并尝试在我的代码中使用带有@Id 注释的字节数组数据类型,但是当我执行代码时它失败并显示错误消息

类型“class model.AbstractEntity”将字段“id”声明为主要字段 键,但不支持“[B”类型的键。

查看 JPA 标准,似乎不支持字节数组作为主键。

我正在编写的代码是运行在 WebSphere 8.5 上的 EJB 的一部分,OpenJPA 由容器提供。不幸的是,我无法更改数据库架构。

所以我的问题是在 JPA 实体类中,当数据库中包含主键的列被定义为“char(16) bit for data”时,我应该使用哪种 Java 数据类型?

我已经查看了这些 SO 问题,但它们对我遇到的问题没有帮助。

更新 根据@Rick 的建议,我创建了一个标识类,其中包含将用于主键的字节数组。但是,每当我尝试将记录保存到表中时,DB2 都会返回错误:

Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: The value of input variable, expression or parameter number "1" cannot be used because of its data type.. SQLCODE=-301, SQLSTATE=07006, DRIVER=3.63.123 {prepstmnt -937290353 INSERT INTO FRAMEWORK.SITE3 (ID, SITE_ADDRESS, SITE_NAME, ROW_VERSION) VALUES (?, ?, ?, ?) [params=(InputStream) java.io.ByteArrayInputStream@94c7f78e, (String) test, (String) test, (int) 1]} [code=-301, state=07006]

身份类的代码如下:

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;

import javax.persistence.Embeddable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;

@Embeddable
@Access(AccessType.FIELD)
public class UniqueId implements Serializable {

    private static final long serialVersionUID = 4458438725376203754L;

    @Column(name="ID")
    private byte[] id;

    public UniqueId() {}

    public UniqueId(byte[] id) {
         this.id = id;
     }

    public UniqueId(String id) {
        this(toByteArray(UUID.fromString(id)));
    }

    @Override
    public String toString() {
        return toUUID(id).toString();
    }

    public static UniqueId fromString(String s) {
        return fromUUID(UUID.fromString(s));
    }

    public static UniqueId fromUUID(UUID uuid) {
        return new UniqueId(toByteArray(uuid));
    }

    private static byte[] toByteArray(UUID uuid) {
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return bb.array();
    }

    private static UUID toUUID(byte[] byteArray) {
        long msb = 0;
        long lsb = 0;
        for (int i = 0; i <8; i++)
            msb = (msb << 8) | (byteArray[i] & 0xff);
        for (int i = 8; i < 16; i++)
            lsb = (lsb << 8) | (byteArray[i] & 0xff);
        UUID result = new UUID(msb, lsb);
        return result;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(id);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        UniqueId other = (UniqueId) obj;
        if (!Arrays.equals(id,  other.id))
            return false;
        return true;
    }

    public static UniqueId generate() {
        return fromUUID(UUID.randomUUID());
    }

}

是否需要向类中添加一些特定的东西来将 ByteArrayInputStream 转换为 DB2 可以理解的东西,或者这应该由 OpenJPA 在内部处理吗?我浏览过 OpenJPA 用户指南,但关于字节数组的使用的信息很少。

【问题讨论】:

    标签: java db2 jpa-2.0 uuid openjpa


    【解决方案1】:

    这个问题在一个邮件列表中得到了深入的回答: mailing list archive

    您不仅需要创建 ID 类,还需要正确注释 ID 列:

    表格类

    @IdClass(ByteArrayId.class)
    @Entity
    @Table(name = "xxx", schema = "yyy")
    public class MediaShare {
    
      @Id
      @Column(name = "ID", columnDefinition = "CHAR(16) FOR BIT DATA NOT NULL")
      private byte[] id;
    }
    

    ID 类:

    import java.util.Arrays;
    
    public class ByteArrayId {
      private byte[] id;
    
      /**
       * Equality must be implemented in terms of identity field equality, and     must use instanceof rather than comparing classes
       * directly (some JPA implementations may subclass the identity class).
       */
      public boolean equals(Object other) {
        if (other == this)
          return true;
        if (!(other instanceof ByteArrayId))
          return false;
    
        ByteArrayId mi = (ByteArrayId) other;
        byte[] comp = mi.id;
        if (id.length != comp.length)
          return false;
        for (int i = 0; i < comp.length; i++)
          if (comp[i] != id[i])
            return false;
        return true;
    
      }
    
      /**
       * Hashcode must also depend on identity values.
       */
      public int hashCode() {
        return Arrays.hashCode( id );
      }
    
      /**
       * Must create Hex-String-Representation of the byte array
       */
      public String toString() {
        StringBuilder ret = new StringBuilder();
        for (Byte b : id) {
          String hexString = Integer.toHexString( b & 0xFF );
    
          // pad values < 16 with leading '0' so that we have 2 characters
          if (hexString.length() == 1)
            ret.append( "0" );
          ret.append( hexString );
        }
    
        return ret.toString();
      }
    
      public byte[] getId() {
        return id;
      }
    
      public void setId(byte[] id) {
        this.id = id;
      }
    }
    

    要搜索 MediaShare,请使用以下 JPQL:

    String sqlString = "SELECT m FROM MediaShare m WHERE m.id=:id";
    Query q = entityManager.createQuery(sqlString);
    q.setParameter ("id", byteArray);
    

    【讨论】:

      【解决方案2】:

      OpenJPA 支持实体作为身份字段,正如参考指南第 4.2 节“作为身份字段的实体”中所讨论的那样。对于具有二进制主键列的旧模式,OpenJPA 还支持使用 byte[] 类型的标识字段。当您使用 byte[] 身份字段时,您必须创建一个身份类。下面介绍了身份类别。

      http://openjpa.apache.org/builds/latest/docs/docbook/manual.html#jpa_overview_pc_identity

      【讨论】:

      • 感谢您的链接,我现在已经创建了一个身份类,但是我无法将记录保存到数据库中。我在原始问题中添加了一些进一步的细节。如果您能看一看,我将非常感激。
      猜你喜欢
      • 2015-08-14
      • 2018-09-08
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 2023-02-24
      • 1970-01-01
      相关资源
      最近更新 更多