Преобразование API JPA2 Criteria .as (String.class) в char (1) - PullRequest
10 голосов
/ 28 июля 2011

Используя критерии API, у меня есть запрос, который делает что-то вроде:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<SourcePath> pathQuery = cb.createQuery(SourcePath.class);
Root<SourcePath> pathRoot = pathQuery.from(SourcePath.class);
pathQuery.where(cb.equal(cb.literal(0x00010002).as(String.class), (pathRoot.get(SourcePath_.path))));

TypedQuery<SourcePath> query = entityManager.createQuery(pathQuery);
query.getResultList();

В результате sql-запроса получится что-то вроде:

select ...snip aliases... from SourcePath where cast(x'00010002', char(1)) = path;

(путь был бы каким-нибудь неприятным старым псевдонимом, но это не имеет значения).

Этот запрос неверен. В частности, приведение: cast(x'00010002', char(1)) не является приведением к строке, как указано .as(String.class), вместо этого оно должно быть либо cast(x'00010002', char), либо cast(x'00010002', char(N), где N - достаточно большое число.

Я выделил причину сбоя приведения в MySqlDialect, предоставленный org.hibernate. В частности:

public String getCastTypeName(int code) {
    if ( code==Types.INTEGER ) {
       return "signed";
    }
     else if ( code==Types.VARCHAR ) {
        return "char";
    }
    ...snip...
}

Который дальше по цепочке интерпретируется как char, который регистрируется в диалоге: registerColumnType( Types.CHAR, "char(1)" );.

Наконец, на мой вопрос. Как я могу обойти это поведение? Должен ли я сообщить об этом как об ошибке в Hibernate? Должен ли я расширить диалог и исправить возвращаемый тип из getCastTypeName? Есть ли альтернатива .as, которая будет правильно разыгрываться? Или я должен использовать строки везде, где я сейчас использую шестнадцатеричные значения, чтобы не касаться крайних случаев реализации hibernate?

Спасибо IDB

1 Ответ

1 голос
/ 16 марта 2012

ИМХО, вы должны использовать строковый литерал, например cb.literal("\u0001\u0002"). Причины:

  1. Это то же самое, что и cb.literal(0x00010002).as(String.class), но менее многословно.
  2. Не попадает ни в один "крайний случай"
  3. Понятнее: обрабатывается ли «0x00010002» в Big Endian или LE? Какую кодировку следует использовать?
  4. Вы можете улучшить разборчивость, используя константы (например: cb.literal(ASCII_SOH + ASCII_STX), где SOH = "\ u0001" и STX = "\ u0002").

РЕДАКТИРОВАТЬ: Добавление лучшего описания, так как я не видел "Или, если я использую строки везде, где я в настоящее время использую шестнадцатеричные значения"

...