Para consultar una base de datos PostgreSQL 10.11, estoy usando jOOQ 3.12.4, que viene incluido con Spring Boot 2.2.
Supongamos que he creado una consulta usando jOOQ como esta:
final String[] ids = ...; final var query = dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(ids)); final Map<String, List<MyTable>> changeDomains = query.fetch().intoGroups(MY_TABLE.ID, MyTable.class);Este código funciona bien y produce los resultados esperados. Pero cuando refactorizo mi consulta e introduzco un parámetro con nombre (para reutilizar la consulta en varias partes de mi código), así:
final String[] ids = ...; final var query = dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(param("ids"))); final Map<String, List<MyTable>> changeDomains = query.bind("ids", ids).fetch().intoGroups(MY_TABLE.ID, MyTable.class);De repente empiezo a recibir el siguiente error:
org.springframework.jdbc.BadSqlGrammarException: jOOQ; bad SQL grammar ...; nested exception is org.postgresql.util.PSQLException: ERROR: operator does not exist: text = character varying[] Hinweis: No operator matches the given name and argument type(s). You might need to add explicit type casts.Editar: me sale el mismo error cuando uso
MY_TABLE.ID.in(param("ids", String[].class))en cambio.
¿Cómo puedo resolver o evitar este problema?
Pero cuando refactorizo mi consulta e introduzco un parámetro con nombre (para reutilizar la consulta en varias partes de mi código)
Si bien podría usar jOOQ de esta manera (¡tenga cuidado al mutar y reutilizar las consultas de jOOQ de una manera que no sea segura para subprocesos!), generalmente se recomienda usar jOOQ de una manera más funcional, consulte, por ejemplo:
No gana mucho reutilizando una consulta jOOQ, específicamente, apenas hay ganancia de rendimiento.
Entonces, en lugar de esto:
final var query = dslContext.selectFrom(MY_TABLE) .where(MY_TABLE.ID.in(param("ids"))); final Map<String, List<MyTable>> changeDomains = query .bind("ids", ids).fetch().intoGroups(MY_TABLE.ID, MyTable.class);Escribe esto:
public ResultQuery<MyTableRecord> query(String[] ids) { return dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(ids)); } // And then: final Map<String, List<MyTable>> changeDomains = query(ids) .fetch().intoGroups(MY_TABLE.ID, MyTable.class); jOOQ, JDBC y SQL no admiten listas IN de valor de enlace único. Si bien parece útil escribir esto:
SELECT * FROM t WHERE c IN (:bind_value) Y pasar una matriz o lista como un valor de enlace único, esto no es compatible con SQL. Algunas API pueden pretender que esto es compatible (pero detrás de escena, reemplace el valor de enlace único por múltiples ?, ?, ..., ?
PostgreSQL admite el operador = ANY (:bind_value) con matrices
SELECT * FROM t WHERE c = ANY (:bind_value)Podrías usarlo en jOOQ usando
dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.eq(any(ids))); De esa forma, podría llamar al método bind() para reemplazar la matriz antes de la ejecución. Sin embargo, sigo recomendando que escriba funciones que devuelvan consultas dinámicamente.