2011-11-21 15 views
9

Si entity.getHistory() es nulo código siguiente fragmento:PostgreSQL JDBC cadena nula tomado como un bytea

(getEntityManager() devuelve resorte inyecta EntityManager, base de datos de tipo historia campo es: texto o varchar2 (2000)

Query query = getEntityManager().createNativeQuery("insert into table_name(..., history, ....) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 
[...] 
.setParameter(6, entity.getHistory()) 
[...] 

query.executeUpdate(); 

Da extraña excepción:

17/11/11 06:26:09:009 [pool-2-thread-1] WARN util.JDBCExceptionReporter:100 - SQL Error: 0, SQLState: 42804 
17/11/11 06:26:09:009 [pool-2-thread-1] ERROR util.JDBCExceptionReporter:101 - ERROR: **column "history" is of type text but expression is of type bytea** 

Consejo: Usted tendrá que volver a escribir o emitir la expresión

.

problema se produjo sólo en esta configuración:
OS: CentOS suelte 5,6 (Final)
Java: 1.6.0_26
DB: PostgreSQL 8.1
controlador JDBC: postgresql-9.1-901.jdbc4
Application Server: Apache -tomcat-6.0.28

Todo funciona bien en algunas otras configuraciones o cuando el historial está vacío. La misma instrucción ejecutada desde pgAdmin funciona bien.

Supongo que el problema está en el controlador PostgreSQL JDBC, ¿hay alguna razón sensata para tratar la cadena nula como un valor bytea? Tal vez algunos cambios extraños entre Postgres 8 y 9?

+0

Sospecho que el EntityManager ha llamado al método 'PreparedStatement.setXXX()' incorrecto para los valores NULL. También podría probar el controlador 8.1 JDBC. Por cierto, ¿sabe que 8.1 ya no es compatible? –

+0

¿Puedes aclarar tus dos primeros párrafos? No parecen tener sentido. –

+0

Mismo código que funciona bien con PostgreSQL 9+ (@a_horse_with_no_name El cliente debe tener 8.1 ...), Windows 7 etc. Si entity.getHistory() es "" en lugar de null, está funcionando. La misma inserción ejecutada desde pgAdmin funciona bien. – laidlook

Respuesta

1

Si usted está dispuesto a utilizar la clase en lugar de la consulta PreparedStatement:

if (entity.getHistory() == null) 
    stmt.setNull(6, Types.VARCHAR); 
else 
    stmt.setString(6, entity.getHistory()); 

(Es posible que el uso de ?::text en su cadena de consulta también quiere trabajar, pero nunca he hecho de esa manera a mí mismo.)

4

Dado que llama al setParameter(int,Object) con un valor nulo, supongo que el administrador de entidades no tiene idea de qué tipo de persistencia usar para vincular el parámetro. Istr Hibernate tiene una predilección por usar SerializableType, que equivaldría a un bytea.

¿Se puede utilizar el método setParameter que toma un objeto Parameter en su lugar, para que pueda especificar el tipo? Realmente no he usado JPA, así que no puedo dar un puntero detallado.

(en mi humilde opinión esta es tu merecido por abusar de interfaz de consulta de SQL nativo del EntityManager hacer inserciones, en lugar de realmente el mapeo de la entidad, o simplemente dejar caer a través de JDBC)

4

Hay una solución sencilla: cuando estás construyendo la cadena de consulta, si un parámetro va a ser nulo, use "nulo" en lugar de "?".

Como @araqnid dice, Hibernate está incorrectamente arrojando valores nulos en el tipo bytea porque no conoce nada mejor.

0

El parámetro JDBC setNull con tipo sql es alternativo para los controladores JDBC heredados que no superan el JDBC Driver Test Suite.

Uno puede protegerse contra errores nulos dentro de la consulta como sigue:

Seleccionar un DE Autor una DONDE: lastName es nulo o INFERIOR (a.lastName) =: lastName

Esto debería funcionar en PostgreSQL después de la solución de este issue.

0

Usando la API específica sesión de Hibernate funciona como una solución:

String sql = "INSERT INTO person (id, name) VALUES (:id, :name)"; 
Session session = em.unwrap(Session.class); 
SQLQuery insert = session.createSQLQuery(sql); 
sql.setInteger("id", 123); 
sql.setString("name", null); 
insert.executeUpdate(); 

También he presentado HHH-9165 para informar de esta cuestión, si es de hecho un error.

+0

note que tuve este problema con un 'Corto' y allí no puede usar' setShort() 'porque toma un' short' no-nulable. Con hibernación 4.x la solución es hacer: '.setParameter (" short ", ShortValue, ShortType.INSTANCE);' (con 3.x creo que es 'Hibernate.SHORT' en lugar de usar' ShortType'). –

Cuestiones relacionadas