Working with PostgreSQL array data types using Hibernate

3

How to perform object retrieval and saving using columns of type array using Hibernate ? In my case I want to save String . How do I set% object_to%? I found the net some examples but they did not work.

My class model extends from another, so it does not implement all methods.

public class ArrayStringType extends TypeHibernate {

    public static final String TYPE = "arrayStringType";

    public Class<String[]> returnedClass() {
        return String[].class;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor sessionImpl, Object obj) throws HibernateException, SQLException {

        Array array = rs.getArray(names[0]);
        return NullUtil.isNull(array) ? null : (String[]) array.getArray(); 
   }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor sessionImpl) throws HibernateException, SQLException {

        Connection connection = st.getConnection();
        String[] stringArray = (String[]) value;

        if (NullUtil.isNull(stringArray)) {
            st.setNull(index, CharArrayType.INSTANCE.sqlType());            
        } else {            
            Array array = connection.createArrayOf("char", stringArray);
            st.setArray(index, array);      
        }

    }

}

Column type and its name in the bank

ufsinss character(2)[]

JDBC Version

postgresql-9.3-1101.jdbc41

You have displayed an error in the userType part.

EDIT 1:

After a little Google, I found the following. The type on this line was wrong, it was raised to nullSafeSet . I discovered looking at Array array = connection.createArrayOf("bpchar", stringArray); . By searching for the array in SO.com using this line nullSafeGet . My problem now is array.getBaseTypeName(); , when the vector comes null.

EDIT 2:

Finally what was missing was to place this code for when nullSet is null. array

Below I will post the answer with the description of the idea. Please feel free to give me an up vote on my answer.

    
asked by anonymous 25.03.2014 / 21:49

2 answers

2

I believe this response of the English OS is just what you need.

A translation would be:

  

I tried some versions based on the Type Array intruded by JDBC4: How can I set a String [] parameter to a native query? . The problem is that Hibernate (at least in version 4.3.1.final) does not work with this new functionality and returned me an error message.

Could not determine a type for class: org.postgresql.jdbc4.Jdbc4Array
  

So I had to make a specific UserType (based on several stackoverflow articles, and other sources)

     

My Model

@Type(type = "fr.mycompany.dao.hibernate.types.ArrayUserType")
private String[] values;
  

My UserType

public class ArrayUserType implements UserType {

    /** Constante contenant le type SQL "Array".
     */
    protected static final int[] SQL_TYPES = { Types.ARRAY };

    /**
     * Return the SQL type codes for the columns mapped by this type. The
     * codes are defined on <tt>java.sql.Types</tt>.
     * 
     * @return int[] the typecodes
     * @see java.sql.Types
     */
    public final int[] sqlTypes() {
        return SQL_TYPES;
    }

    /**
     * The class returned by <tt>nullSafeGet()</tt>.
     * 
     * @return Class
     */
    public final Class returnedClass() {
        return String[].class;
    }

    /**
     * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
     * should handle possibility of null values.
     * 
     * @param resultSet a JDBC result set.
     * @param names the column names.
     * @param session SQL en cours.
     * @param owner the containing entity 
     * @return Object
     * @throws org.hibernate.HibernateException exception levée par Hibernate
     * lors de la récupération des données.
     * @throws java.sql.SQLException exception SQL 
     * levées lors de la récupération des données.
     */
    @Override
    public final Object nullSafeGet(
            final ResultSet resultSet, 
            final String[] names, 
            final SessionImplementor session, 
            final Object owner) throws HibernateException, SQLException {
        if (resultSet.wasNull()) {
            return null;
        }

        String[] array = (String[]) resultSet.getArray(names[0]).getArray();
        return array;
    }

    /**
     * Write an instance of the mapped class to a prepared statement. Implementors
     * should handle possibility of null values. A multi-column type should be written
     * to parameters starting from <tt>index</tt>.
     * 
     * @param statement a JDBC prepared statement.
     * @param value the object to write
     * @param index statement parameter index
     * @param session sql en cours
     * @throws org.hibernate.HibernateException exception levée par Hibernate
     * lors de la récupération des données.
     * @throws java.sql.SQLException exception SQL 
     * levées lors de la récupération des données.
     */
    @Override
    public final void nullSafeSet(final PreparedStatement statement, final Object value, 
            final int index, final SessionImplementor session) throws HibernateException, SQLException {

        if (value == null) {
            statement.setNull(index, SQL_TYPES[0]);
        } else {
            String[] castObject = (String[]) value;
            Array array = session.connection().createArrayOf("text", castObject);
            statement.setArray(index, array);
        }
    }

    @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 arg0, final Object arg1)
            throws HibernateException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public final Serializable disassemble(final Object arg0) throws HibernateException {
        // TODO Auto-generated method stub
        return null;
    }

    @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;
    }
 }
  

And in the end, but not least, when I need to run Native Queries of SQL, I have to focus on the parameter type with the following syntax:

String[] values = ...
Type arrayType = new CustomType(new ArrayUserType());
query.setParameter("value", values, arrayType);
28.03.2014 / 14:09
0

First, I would like to thank the above user who posted me the answer, as I had been working on this solution for the company where I work for a few days. First I was using my database case postgres , and one of the tables was demarcated with the char[2] data type. That's right, a vector of char with size 2. The first thing was to look for something related and found that Hibernate does not have native support, so it would be necessary to converter . In this case using the class I'm posting already implements UserType , where it was only necessary to implement the methods nullSafeGet and nullSafeSet besides returnedClass .

Then we first implemented the nullSafeGet that looks for the database object.

public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor sessionImpl, Object obj) throws HibernateException, SQLException {

        Array array = rs.getArray(names[0]);        
        return NullUtil.isNull(array) ? null : (String[]) array.getArray(); 
   }

The first line takes the object and assigns it to a array of class java.sql.array . I draw attention to the possibility of this way of finding out what kind of data Hibernate works from your column to be used in nullSafeSet . In this way the user will have a return of type in the String, only for test, remembering that the column must have some value filled, because if it does not it will generate a nullPointerException .

String tipoDaColuna = array.getBaseTypeName();

The returned type was bpchar , so we started to implement the nullSafeSet method.

public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor sessionImpl) throws HibernateException, SQLException {    

    Connection connection = st.getConnection();
    String[] stringArray = (String[]) value;

    if (NullUtil.isNull(stringArray)) {
        st.setNull(index, Types.ARRAY);
    } else {            
        Array array = connection.createArrayOf("bpchar", stringArray);
        st.setArray(index, array);      
    }
}

This method looks up the vector, if it is null, I hedge the column as null of type array , otherwise I set the vector as you see above.

The data type in the model is as String[] ufs .

Library calls were.

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 org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;

That's it, thanks!

    
30.03.2014 / 13:36