postgresql中text / array中的contains / in的Hibernate标准

问题描述 投票:0回答:1

我有一个名为box的实体。每个框包含一些参数,对于许多唯一ID可以是相同的。唯一ID只是数字,没有任何其他角色。所以我在postgresql和Java中创建了它们作为文本数组我将它们作为ArrayList并使用自定义用户类型映射它们。 package com.geniedoc.utils;

import java.io.Serializable;
import java.sql.Array;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
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.usertype.UserType;

public class PostgresTextArrayType implements UserType {

    protected static final int[] SQL_TYPES = {Types.ARRAY};
     public Class<String> returnedClass() {
            return String.class;
        }

     public final int[] sqlTypes() {
            return SQL_TYPES;
        }


        @Override
        public Object nullSafeGet(ResultSet resultSet, String[] names,
                SessionImplementor arg2, Object arg3)
                throws HibernateException, SQLException {
             List<String> list = null;
            String nameVal = resultSet.getString(names[0]);
             if (nameVal != null) {
                 nameVal = nameVal.substring(1,nameVal.length()-1);
                 list = new ArrayList<>();
                 StringTokenizer tokenizer = new StringTokenizer(nameVal, ",");
                 while (tokenizer.hasMoreElements()) {
                     String val = (String) tokenizer.nextElement();
                     list.add(val);
                 }
             }

             return list;

        }

        @Override
        public void nullSafeSet(PreparedStatement statement, Object value, int index,
                SessionImplementor arg3) throws HibernateException,
                SQLException {
             Connection connection = statement.getConnection();
                if (value == null) {
                    statement.setNull(index, SQL_TYPES[0]);
                } else {
                    System.out.println("statement>>>>"+statement);
                    System.out.println("value>>>>"+ value);
                    System.out.println("index>>>>"+index);
                    @SuppressWarnings("unchecked")
                    ArrayList<String> parameter=new ArrayList<>();
                    if(value instanceof Array)
                    {   parameter=(ArrayList<String>) value;
                    }else
                    { 
                        parameter.add((String) value);
                    }
                    ArrayList<String> list=parameter;
                    String[] castObject = Arrays.copyOf(list.toArray(), list.toArray().length, String[].class);
                    Array array = connection.createArrayOf("text", castObject);
                    statement.setArray(index, array);
                    System.out.println("statement>>>>"+statement);
                }
        }
        @Override
        public final Object deepCopy(final Object value) throws HibernateException {
            return value;
        }

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

        @Override
        public final Object assemble(final Serializable serializable, final Object arg1)
                throws HibernateException {
             return serializable;
        }

        @Override
        public final Serializable disassemble(final Object o) throws HibernateException {
            return (Serializable) o;
        }

        @Override
        public final boolean equals(final Object x, final Object y) throws HibernateException {
            if (x == y) {
                return true;
            } else if (x == null || y == null) {
                return false;
            } else {
                return x.equals(y);
            }
        }

        @Override
        public final int hashCode(final Object x) throws HibernateException {
            return x.hashCode();
        }

        @Override
        public final Object replace(
            final Object original,
            final Object target,
            final Object owner) throws HibernateException {
            return original;
        }
          private String serialize(List<String> list) {
                StringBuilder strbul = new StringBuilder();
                Iterator<String> iter = list.iterator();
                strbul.append("{");
                while (iter.hasNext()) {
                    strbul.append(iter.next());
                    if (iter.hasNext()) {
                        strbul.append(",");
                    }
                }
                strbul.append("}");
                return strbul.toString();
            }


}

这是我的休眠标准: -

    Session session=getSession();
    Criteria criteria=session.createCriteria(Box.class);
    criteria.add(Restrictions.in("unique_id", unique_id));
    return (Unit)criteria.uniqueResult();

我需要获取包含特定唯一ID的Box。但它不起作用。仅当我在DB中的文本数组中有一个值时,它才返回结果。但如果我在DB中有多个值,则不会显示任何结果。

任何帮助表示赞赏。

java arrays postgresql hibernate
1个回答
0
投票

实施UserType通常不值得努力。你最好将@PrePersist@PreUpdate@PostLoad函数添加到你的类中,因为Postgres接受数组的字符串格式。由于它只是数字,因此转换非常简单。

@Transient
private long[] theids;

@Column(name = "the_ids")
private String therealids;

@PrePersist
@PreUpdate
private void encode() {
    therealids = "{" + java.util.Arrays.toString(theids) + "}";
}

@PostLoad
private void decode() {
    String[] ids = therealids.split(",");
    theids = new long[ids.length];
    if (ids.length == 0) {
        return;
    }
    int last = ids.length - 1;
    // remove the "{"
    ids[0] = ids[0].substr(1);
    // remove the "}"
    ids[last] = ids[last].substr(0, ids[last].length() - 1);
    for (int i = 0; i < ids.length; i++) theids[i] = Long.parseLong(ids[i]);
}

您可以对此代码进行至少4次优化,以使其更快,更少占用内存,但这是简短版本。

如果你想做同样的事情,但是使用字符串数组,你必须非常了解该场景中数组的正确转义语法,更糟糕的是,可选的双引号。

© www.soinside.com 2019 - 2024. All rights reserved.