JPA-запрос, возвращающий нули - составной ключ с нулевым столбцом

У меня есть устаревшая база данных (на самом деле файлы Cobol), к которой я обращаюсь с помощью проприетарного драйвера JDBC с Hibernate/JPA.

У сущности есть составной первичный ключ с 2 столбцами: CODE а также SITE,

В устаревших данных есть записи для того же CODE которые могут иметь либо конкретное значение для SITE или может быть запись с NULL в SITE столбец, который представляет "Все сайты". Теория этого файла, если вы не можете найти CODE для вашего конкретного SITE Затем вы ищите запись с NULL в SITE ("ловушка для всех").

Я не могу изменить структуру этой "таблицы", поскольку она потребует переписывания больших частей устаревшей системы Cobol, чего мы не хотим делать. Я также не могу создавать представления данных.

Теперь, когда я делаю em.find с первичным составным классом ключей, содержащим определенный code и ноль для site затем Hibernate правильно находит соответствующую запись со значением NULL в столбце - все хорошо!

Но если я попытаюсь сделать запрос, используя em.createQuery похож на следующее:

SELECT x FROM TareWeight x WHERE x.pk.code = 'LC2'

для которого есть 2 записи, он возвращает нулевой объект в результирующем списке для записи с NULL в SITE колонка.

Если я возьму SQL, который Hibernate использует для этого запроса, то "база данных" возвращает две записи: одну с сайтом NULL, а другую с конкретным сайтом. Похоже, что когда Hibernate загружает сущности из этих результатов, он отображает его на нулевой объект сущности.

Так что либо Hibernate поддерживает, либо нет. Почему бы em.find работать, но не em.createQuery?

Я знаю, что этот вопрос похож, но ответы, похоже, предполагают, что это невозможно. Но ясно, что Hibernate может сделать поиск правильно, так почему запрос не работает?


РЕДАКТИРОВАТЬ: ОК, поэтому я нашел NullableStringType определение класса в этом выпуске Hibernate JIRA и добавление его в мой проект.

Если я добавлю @Type определение на site столбца PK, используя этот тип класса, то я могу успешно получить ненулевые сущности обратно из запроса SELECT, с помощью site поле, содержащее любой текст строки, который я определяю как представление null,

Тем не менее, он по-прежнему ведет себя по-другому. find возвращает сущность с site поле, содержащее null, но запрос возвращает сущность с site поле, содержащее "NaN" (представление по умолчанию null).

Такое ощущение, что они должны вести себя одинаково.


ОБНОВЛЕНИЕ 2: Некоторые из вас хотят знать особенности рассматриваемой "базы данных".

Это движок Genesis RDBMS, написанный Trifox Inc. Данные хранятся в индексированных файлах AcuCobol (теперь Micro Focus) Vision.

У нас есть конфигурация для перевода пустых (SPACES) буквенно-цифровых полей в NULL, поэтому наши файловые записи, содержащие пробелы для поля PK, переводятся в NULL. Я могу специально выбрать соответствующую запись с помощью WHERE site_id IS NULLТаким образом, СУБД обрабатывает эти пустые поля как SQL NULL.

Сказав все это, я не верю, что эта проблема имеет какое-либо отношение к "базе данных", за исключением того факта, что необычные поля PK имеют нулевое значение.

Более того, если я войду в SQL, который Hibernate использует для обоих find и запрос, они практически идентичны.

Вот SQL для поиска:

select tareweight0_.CODE as CODE274_0_, tareweight0_.SITE as SITE274_0_, 
       tareweight0_.WEIGHT as WEIGHT274_0_ from TARE_WEIGHT tareweight0_ 
       where tareweight0_.CODE=? and tareweight0_.SITE=?

И вот SQL для запроса:

select tareweight0_.CODE as CODE274_, tareweight0_.SITE as SITE274_, 
       tareweight0_.WEIGHT as WEIGHT274_ from TARE_WEIGHT tareweight0_ 
       where tareweight0_.CODE=? and tareweight0_.SITE=?

Как видите, единственное отличие - это псевдонимы столбцов.


ОБНОВЛЕНИЕ 3: Вот некоторые примеры данных:

select code, site, weight from tare_weight where code like 'LC%';

 CODE   SITE    WEIGHT
 ------ ------ -------
 LC1               .81
 LC2               .83
 LC2    BEENLH     .81
 LC3              1.07
 LC3    BEENLH    1.05
 LC4              1.05
 LCH1              .91
 LCH2              .93
 LCH2   BEENLH     .91
 LCH6             1.13
 LCH6   BEENLH    1.11

И поиск специально для NULL:

select code, site, weight from tare_weight where code like 'LC%' and site IS NULL;

 CODE   SITE    WEIGHT
 ------ ------ -------
 LC1               .81
 LC2               .83
 LC3              1.07
 LC4              1.05
 LCH1              .91
 LCH2              .93
 LCH6             1.13

1 ответ

"Так что либо они поддерживают, либо нет"

TL; DR Это ожидание / чувство неоправданно. Неподдерживаемая функциональность в вашей ссылке (и моя ниже) - именно ваша. "Не поддерживать" означает, что если вы делаете это, то Hibernate может делать все, что угодно. Вам повезло, что они (кажется) возвращают разумные значения. (Хотя это всего лишь предположение, как они действуют. У вас нет спецификации.) Нет никаких оснований ожидать чего-либо, не говоря уже о последовательности. Когда поведение является просто следствием возникновения какого-либо неподдерживаемого случая, любое "почему", скорее всего, является просто артефактом того, как код был написан с учетом других случаев.


Вот (n старая) ветка поддержки, на которую отвечает Hibernate Team:

Заголовок сообщения: составной ключ с нулевым значением для одного столбца
PostPosted: Пн Июл 03, 2006 2:21

У меня есть таблица с составным первичным ключом, и я создал следующее сопоставление для таблицы. Так как можно вставить нулевое значение для любого столбца в составном ключе, если комбинация всех столбцов является уникальной, у меня есть запись в таблице, которая имеет нулевое значение для столбца V_CHAR2 (который является частью составного ключа) . когда я выполняю запрос к этой сущности, я получаю нулевые значения для записей, имеющих нулевое значение столбца V_CHAR2. Что не так в моем отображении и реализации..

Опубликовано: вторник, 11 июля 2006 г., 9:09
Hibernate Team

первичный ключ не может быть нулевым (ни полностью, ни частично)

Опубликовано: суббота, 6 января 2007 г., 5:35
Hibernate Team

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

Это неудивительно, потому что NULL не разрешен в столбце PK в SQL. Декларация PRIMARY KEY является синонимом UNIQUE NOT NULL. NULL не равен чему-либо с (ошибочным) намерением, что неизвестное значение не известно как равное. (Ваши ожидания какого-либо исключения по крайней мере в некоторых случаях для NULL в PK, равного NULL в условии, противоречат SQL.) Учитывая, что NULL не допускается в значениях PK, мы можем ожидать оптимизацию PK, связанную с 1:1 сопоставления и наборы, а не наборы строк, предполагающие отсутствие пустых значений, когда это удобно. Можно ожидать, что Hibernate решил не беспокоиться о том, что их реализация сделала со случаями, которые не должны возникать в SQL. Жаль, что они не говорят вам об этом при компиляции или исполнении. Надеюсь, это в документации.)

Четное find отличается от createQueryNULL не удивительно. Первое включает в себя одно значение, в то время как второе включает в себя наборы (а не пакеты) строк без NULL (но не) .

Обходной путь может заключаться в том, чтобы не обрабатывать столбцы первичного ключа как NULL, а как фактическую строку пробелов в хранилище. (Независимо от того, что это означает, учитывая ваше хранилище / СУБД /hibernate/JPA/Java стек. Вы не предоставили нам достаточно информации, чтобы знать, будет ли затруднено ваше представление базы данных Cobol из-за того, что пространство JPU не будет отображено для вашего JPA). С вашими данными вы все равно можете объявить уникальный столбец по столбцам.

Другие вопросы по тегам