Вопрос

Можно ли выполнить запрос критериев JPA, используя оператор Oracle Text's Socide, и если да, то как?

Это было полезно?

Решение

Сомневаюсь. API существует во всех RDBMS и предоставляет определенные конструкции, такие как «как»/«подстроение», которые могут быть сопоставлены с чем -то из этой формы при использовании в Oracle для текстового столбца, но затем они могут просто использовать стандартный SQL. Нет стандартного способа настаивать на этом

Другие советы

Критерии поддерживают API функции (), который позволяет вызывать функцию базы данных по имени.

qb.gt(qb.function("CONTAINS", root.get("name"), qb.parameter("name"), qb.literal(1)), 1)

Eclipselink также поддерживает это в JPQL, используя ключевое слово Func.

Я только что написал OracleTextDictionary для OpenJPA, который преобразует обычные «как» операторы в «содержит» операторов, когда аргумент префикс с «волшебным» маркером.

Таким образом, можно использовать язык QueryDSL или критерии (или JPQL) с Oracle Text.

Словарь обнаруживает как утверждения с магическим маркером в аргументе, и переписывает SQL, чтобы использовать CTX, содержит вызов.

Одним из недостатков является то, что счет недоступен простым способом, но было бы возможно улучшить драйвер до заказа по счету. Не стесняйтесь редактировать код :-)

Я предполагаю, что можно переносить в спячку, предполагая, что существует аналогичный механизм для настройки запросов базы данных для определенного БД.

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 = "@CTX@";
    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;
    }



}

Пример: следующий (очевидно надуванный) входной вход вызывается с параметрами:

:1 "@CTX@omg near ponies"
:2 "@CTX@rainbow"
:3 "@CTX@rain%"
:4 "abc1%"                     <-- an ordinary like :-)
:5 "@CTX@mushroom%"  

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 <= ?

В качестве примечания: QueryDsl фактически имеет оператор «Конфим», предположительно для бэкэнда Lucene, для которого Backends JPA и SQL генерирует заявление «подобно».

Я не выяснил способ перегрузки оператора, чтобы его можно было использовать. (Кроме переписывания кода, который я не могу сделать, так как я использую версию, связанную с WebSphere.)

Итак, я прибегаю к маленькому статическому методу, чтобы он выглядел хорошо при использовании Quertydsl.

// x.where(c.custName.like(CTX.contains("omg near ponies"))));

Было бы еще лучше, если бы JPQL мог бы предоставить некоторые абстракции (или плагины) для полных текстовых поисковых систем ...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top