1

我有一个类,它的字段引用了一个固定大小的整数数组:

class Tracking{
    private int[] tracks;
}

使用 JPA(由 Hibernate 支持)将轨道字段映射到数据库的最佳方法是什么?

轨道数组将始终包含 10 个元素。我知道@ElementCollection 注释,但这意味着我最终会得到两个表(Tracking 和 Tracking_tracks),这似乎是不必要的。

想到的唯一方法是使用一个字符串字段将 10 个数字映射到一个用冒号分隔的字符串。我将使该字段持久化(一个简单的基本@Column),然后在getter 和setter 中执行解析为int []。

有什么建议么?我只想要一种有效的方式来保存这些信息。Tracking 对象将永久生成,会有数千个,并且由于整数的数量始终为 10,因此将它们保存到单独的表中并执行连接和选择以检索它们似乎有点过分了。

4

2 回答 2

2

这可能取决于您的持久性提供程序。但是您可以尝试使用特殊的列定义并让您的持久性提供程序处理转换。如果这不起作用,许多持久性提供程序支持自定义类型。在休眠中,它们被称为用户类型,open jpa 使用自定义字段映射。您的数据库可能支持原始固定大小的字节存储。

于 2013-05-31T20:31:05.467 回答
0

根据 SpaceTrucker 关于 Hibernate UserType 的建议,这里是提供 Hibernate 自定义 UserType 所需的完整代码(非常感谢Kunaal A Trehan的博客文章中提供了此类所基于的代码):

package org.mypackage;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
import org.hibernate.usertype.UserType;
import org.springframework.util.ObjectUtils;


/**
 * An Hibernate {@link UserType} that allows persisting a list of integers in one single column in the table.
 * Based in code from http://javadata.blogspot.com.ar/2011/07/hibernate-and-user-types.html.
 * 
 * In order to use this as the mapper for a column, use the following in the field of your entity:
 *  @Type(type=IntegerListUserType.NAME)
 *   List<Integer> tracks;
 *  
 * @author dds
 * */
public class IntegerListUserType implements UserType {

    public static final String NAME = "org.mypackage.IntegerListUserType"; //WARNING this must match class name!


    @Override
    public int[] sqlTypes() {
        return new int[] { Types.VARCHAR };
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass() {
        return List.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return ObjectUtils.nullSafeEquals(x, y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        if (x != null)
            return x.hashCode();
        else
            return 0;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names,
            SessionImplementor session, Object owner)
            throws HibernateException, SQLException {
        List<Integer> list = null;
        String nameVal = rs.getString(names[0]);
        if (nameVal != null) {
            list = new ArrayList<Integer>();
            StringTokenizer tokenizer = new StringTokenizer(nameVal, ",");
            while (tokenizer.hasMoreElements()) {
                String number = (String) tokenizer.nextElement();
                list.add(Integer.valueOf(number));
            }
        }
        return list;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index,
            SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
        } else {
            st.setString(index, serialize((List<Integer>) value));
        }
    }

    private String serialize(List<Integer> list) {
        StringBuilder strbul = new StringBuilder();
        Iterator<Integer> iter = list.iterator();
        while (iter.hasNext()) {
            strbul.append(iter.next());
            if (iter.hasNext()) {
                strbul.append(",");
            }
        }
        return strbul.toString();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        if (value == null)
            return null;
        else {
            List<Integer> newObj = new ArrayList<Integer>();
            List<Integer> existObj = (List<Integer>) value;
            newObj.addAll(existObj);
            return newObj;
        }
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        Object deepCopy = deepCopy(value);
        if (!(deepCopy instanceof Serializable))
            return (Serializable) deepCopy;
        return null;
    }

    @Override
    public Object assemble(Serializable cached, Object owner)
            throws HibernateException {
        return deepCopy(cached);
    }

    @Override
    public Object replace(Object original, Object target, Object owner)
            throws HibernateException {
        return deepCopy(original);
    }

}

请注意,为了简单起见,我将 String 转换为 List < Integer > 而不是 int[] 。

于 2013-07-26T18:02:00.717 回答