¿Es posible realizar una consulta de criterios JPA utilizando la instrucción contains de Oracle Text y, de ser así, cómo?Oracle Text Criteria Query en JPA
Respuesta
Doubt it. La API está presente en todos los RDBMS y proporciona ciertas construcciones como "LIKE"/"SUBSTRING" que podrían asignarse a algo de esa forma cuando se usan en Oracle para una columna TEXT, pero de nuevo pueden usar estándar SQL. No existe una manera estándar de insistir en eso
Acabo de escribir un OracleTextDictionary para openjpa, que convierte operadores comunes 'similares' en operadores 'contains', cuando el argumento está prefijado con un marcador "mágico".
De esta manera, es posible utilizar QueryDSL o Criteria Language (o JPQL) con texto de Oracle.
El diccionario detecta declaraciones LIKE con un marcador mágico en el argumento, y reescribe el SQL para usar una llamada CTX CONTAINS.
Una desventaja es que el puntaje no es accesible de una manera simple, pero sería posible mejorar el controlador para ordenar por puntaje. Siéntase libre de editar el código :-)
Supongo que es posible migrar a puerto, suponiendo que hay un mecanismo similar para ajustar las consultas de la base de datos a un db específico.
package se.grynna.dict;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.sql.OracleDictionary;
import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select;
public class OracleTextDictionary extends OracleDictionary {
public static final String CTX_MAGIC_MARKER = "@[email protected]";
final static Pattern likePattern = Pattern
.compile("t(\\d+)\\.(\\S+) LIKE (\\?)");
@Override
protected SQLBuffer toSelect(SQLBuffer select,
JDBCFetchConfiguration fetch, SQLBuffer tables, SQLBuffer where,
SQLBuffer group, SQLBuffer having, SQLBuffer order,
boolean distinct, boolean forUpdate, long start, long end,Select sel) {
SQLBuffer sqlBuffer = super.toSelect(select, fetch, tables, where,
group, having, order, distinct, forUpdate, start, end, sel);
SQLBuffer tmpBuf = sqlBuffer;
String sql = tmpBuf.getSQL();
int label = 1;
for (Matcher m = likePattern.matcher(sql); m.find(); sql = tmpBuf.getSQL()) {
int argPos = m.start(3);
int argIdx = findArgIdx(sql, argPos);
Object o = tmpBuf.getParameters().get(argIdx);
if(o == null) break;
String arg = o.toString();
if (arg.startsWith(CTX_MAGIC_MARKER)) {
if (tmpBuf == sqlBuffer) {
tmpBuf = new SQLBuffer(sqlBuffer);
}
arg = arg.substring(CTX_MAGIC_MARKER.length());
setParameter(tmpBuf, argIdx, arg);
String aliasNo = m.group(1);
String colName = m.group(2);
}
String replace = String.format("(CONTAINS(t%s.%s,?,%d)>0)",
aliasNo, colName, label++);
tmpBuf.replaceSqlString(m.start(), m.end(), replace);
m.reset(tmpBuf.getSQL());
}
}
return tmpBuf;
}
@SuppressWarnings("unchecked")
private void setParameter(SQLBuffer tmpBuf, int argIdx, String arg) {
tmpBuf.getParameters().set(argIdx, arg);
}
private int findArgIdx(String sql, int argPos) {
int count = -1;
for (int i = 0; i <= argPos; i++) {
char c = sql.charAt(i);
if (c == '?') {
count++;
}
}
return count;
}
}
Ejemplo: El siguiente entrada (obviamente artificial) produce se llama con los parámetros:
:1 "@[email protected] near ponies"
:2 "@[email protected]"
:3 "@[email protected]%"
:4 "abc1%" <-- an ordinary like :-)
:5 "@[email protected]%"
JPQL
select distinct customer
from Customer customer
where customer.custName like :a1 and customer.custName like :a2 and customer.custName like :a1 and customer.custId in (select d.custId
from Customer d
where d.custName like :a3 or d.custName like :a1)
SQL
SELECT t0.custId,
t0.custName
FROM Customer t0
WHERE ((CONTAINS(t0.custName,?,1)>1)
AND (CONTAINS(t0.custName,?,2) >1)
AND (CONTAINS(t0.custName,?,3) >1)
AND t0.custId IN
(SELECT t1.custId
FROM Customer t1
WHERE (t1.custName LIKE ? <---- the like survives....
OR (CONTAINS(t1.custName,?,1)>1))
))
AND ROWNUM <= ?
Como una nota : QueryDsl en realidad lo hace tener un operador'contains ', supuestamente para el backend Lucene, para el cual los backends jpa y sql generan una declaración' like '.
No he encontrado una forma de sobrecargar el operador contains, para que pueda ser utilizado. (Aparte de reescribir el código, que no puedo hacer porque estoy usando la versión incluida con WebSphere.)
Por lo tanto, recurro a un pequeño método estático para que se vea bien cuando se utiliza QuertyDSL.
// x.where(c.custName.like(CTX.contains("omg near ponies"))));
Sería aún mejor si JPQL podría proporcionar algunas abstracciones (o plugins) para los motores de búsqueda de texto completo ...
Criterios soporta una API() la función que permite a una función de base de datos para ser llamado por nombre.
qb.gt(qb.function("CONTAINS", root.get("name"), qb.parameter("name"), qb.literal(1)), 1)
EclipseLink también lo admite en JPQL utilizando la palabra clave FUNC.
- 1. NHibernate Criteria Query - Select Distinct
- 2. Hibernate Query vs Criteria Performance
- 3. Creación de consultas utilizando Criteria API (JPA 2.0)
- 4. Oracle SQL Query logging
- 5. Oracle Uptime Query
- 6. Oracle date "Between" Query
- 7. Hibernate Query Hints para JPA
- 8. JPA Query funciones MES/AÑO
- 9. oracle blob text search
- 10. Seleccionar columnas específicas en jpa 2 Criteria API?
- 11. Oracle query tiempo de ejecución
- 12. Eliminar con "Unir" en Oracle sql Query
- 13. Consulta dinámica de JPA 2.0 con la API de Criteria
- 14. Simulación de larga data Oracle DB query
- 15. Hibernate criteria api 'Seleccionar'
- 16. Oracle CLOB y JPA/Hibernate ¿ORDEN POR?
- 17. Oracle 11g: Índice no utilizado en "select distinct" -query
- 18. Usando JPA 2.0 Criteria API y el molde causa que JPQL generado falle en Hibernate
- 19. Alternativa más utilizable a Criteria API
- 20. cómo almacenar la fecha Y hora con JPA en Oracle?
- 21. NHibernate Criteria Collection Contiene
- 22. Oracle PL/SQL Query Order Por problema con Distinct
- 23. Countif With Multiple OR Criteria
- 24. Usar groupProperty y countDistinct en Grails Criteria
- 25. instrucción CASE en HQL o Criteria
- 26. Coalesce equivalente en la consulta Hibernate Criteria?
- 27. Colección existe Criteria en WCF Data Services
- 28. JPA CriteriaQuery OneToMany
- 29. Java Crosstab - preparedstatement query
- 30. RODBC Query Tuning
Así que supongo que tengo que recurrir a una consulta nativa de JPA mediante la concatenación de cadenas y olvidar la seguridad del tipo. Ay. – Ryan