Hibernate, Postgres y tipo de matriz

Estoy atascado en un problema específico utilizando el tipo de matriz en postgresql 9.3 mapeado con hibernate 4.1.0. Este tipo me permite tener un modelo de datos realmente sólido, sin crear muchas tablas y uniones.

Para mapear un campo almacenado con este tipo particular, he usado un UserType

De todos modos, funciona bien con hibernación pura (hql) pero también necesito enviar consultas nativas de sql a mi base de datos. Cuando lo hago, a pesar de muchos bashs, no he encontrado ninguna manera de hacerlo.

Intento muchas syntax basadas en esto

String[] values = {"value1", "value2"}; String queryString = "SELECT * FROM instances WHERE values && :values"; Query query = this.getSession().createSQLQuery(queryString).addEntity(Instance.class); query.setParameterList("values", values); query.list(); 

Tengo el operador no existe: el texto [] y el carácter varían

Debe dar la siguiente syntax en jdbc: [‘value1’, ‘value2’] y parece dar ‘value1’ …

Intenté muchas syntax con

  • Colección
  • Arrays puros
  • syntax [: values]: obtuve un error de syntax cerca de “[”

Necesito enviar una consulta nativa porque utilizo la Vista Materializada para boost el rendimiento.

Mi consulta SQL funciona en la consola postgresql. Por lo tanto, es un problema específico de hibernación.

Probé algunas versiones basadas en el tipo de matriz introducido por JDBC4: ¿cómo puedo establecer un parámetro String [] en una consulta nativa? . El problema también es que Hibernate (incluso en la última versión 4.3.1.final) no funciona con estas nuevas características y me dio el siguiente mensaje de error

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

Así que tuve que hacer un UserType específico (basado en varios artículos en stackoverflow y otras fonts)

Mi modelo

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

Mi ArrayUserType

 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 java.sql.Types. * * @return int[] the typecodes * @see java.sql.Types */ public final int[] sqlTypes() { return SQL_TYPES; } /** * The class returned by nullSafeGet(). * * @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 index. * * @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; } 

}

Y el último, pero el menos (eso es lo que me perdí): cuando necesito ejecutar SQL Native Query, tengo que forzar el tipo de parámetro con la siguiente syntax

 String[] values = ... Type arrayType = new CustomType(new ArrayUserType()); query.setParameter("value", values, arrayType);