У меня есть устаревшая база данных (фактически файлы Cobol), к которой я обращаюсь, используя запатентованный JDBC-драйвер с Hibernate/JPA.JPA Query возвращает nulls - Composite Key с нулевым столбцом
Объект имеет составной первичный ключ с 2 столбцами: CODE
и SITE
.
В унаследованных данных имеются записи для одной и той же CODE
, которые могут иметь либо конкретное значение для SITE
, или может быть запись с NULL в SITE
столбце, который представляет «Все сайты». Теория этого файла, если вы не можете найти CODE
для своего конкретного SITE
, то вы просматриваете запись с помощью NULL в SITE
(«catch-all»).
Я не могу изменить структуру этой «таблицы», поскольку это потребует перезаписи больших частей старой системы Cobol, которую мы не хотим делать. Я также не могу создавать представления данных.
Теперь, когда я делаю em.find
с первичным ключом класса композит, содержащий конкретный code
и нуль для site
, то Hibernate правильно находит запись соответствия со значением NULL в столбце - Все хорошо!
Но если я пытаюсь сделать запрос, используя em.createQuery
, подобный следующему:
SELECT x FROM TareWeight x WHERE x.pk.code = 'LC2'
, для которых есть 2 записей, она возвращает пустой объект в результирующий список для записи с NULL в SITE
column.
Если я беру SQL, который Hibernate использует для этого запроса, тогда «база данных» возвращает две записи: одну с сайтом NULL и одну с определенным сайтом. Похоже, что когда Hibernate загружает Entities из этих результатов, он сопоставляет его с нулевым объектом Entity.
Так что либо Hibernate поддерживает его, либо нет. Почему бы работать em.find
, но не em.createQuery
?
Я знаю, что this question аналогичен, но ответы, похоже, предполагают, что это невозможно. Но ясно, что Hibernate может правильно найти, так почему запрос не работает?
EDIT: ОК, так что я нашел определение в NullableStringType
класс на this Hibernate JIRA Issue и добавить его в мой проект.
Если добавить @Type
определения на site
колонки ПК с помощью этого класса типа, то я могу успешно получить ненулевые Сущности назад от SELECT, запроса, с site
поля, содержащего все, что строка текстом я определяю как представление от null
.
Однако он по-прежнему ведет себя по-другому. find
возвращает объект с полем site
, содержащим null
, но запрос возвращает объект с полем site
, содержащим «NaN» (представление по умолчанию null
).
По-прежнему кажется, что они должны вести себя одинаково.
UPDATE 2: Некоторые из вас хотят знать особенности о «базе данных» в вопросе.
Это движок Genesis RDBMS, написанный Trifox Inc.. Данные хранятся в файлах AcuCobol (теперь Micro Focus) Vision.
У нас есть набор настроек для перевода пустых (SPACES) буквенно-цифровых полей в NULL, поэтому наши записи файлов, содержащие пробелы для поля PK, переводятся в NULL. Я могу специально выбрать соответствующую запись, используя WHERE site_id IS NULL
, поэтому RDBMS обрабатывает эти пустые поля как 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=?
Как вы можете видеть, единственное различие в названиях столбца псевдонимов.
UPDATE 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
Если вы сравниваете поиск по вашему запросу, не следует ли в предикате вашего запроса «x.pk.site равно null»? Я знаю, что это не отвечает на ваш вопрос о том, почему запрос возвращает весь нулевой объект, но что-то, что нужно учитывать при попытке отладить поведение между этими двумя подходами. – dispake
Справедливый комментарий. Поэтому, если я добавлю предложение where и AND.pk.site IS NULL, я все равно получаю единственный нулевой объект в результирующем списке. Таким образом, они по-прежнему ведут себя по-разному, даже несмотря на то, что SQL теперь по существу тот же. Следует отметить, что запрос находит правильное количество записей, а в результирующем списке всегда содержится правильное количество записей, просто они равны нулю, если столбец сайта равен нулю. – DuncanKinnear
Что такое ваша СУБД? Также, пожалуйста, покажите некоторые данные примера. Пожалуйста, прекратите использовать «null», когда база данных фактически не содержит SQL NULL или когда соответствующее значение Java используется в типах Nullable. NULL обрабатывается специально SQL, как и NaN Java. Прежде всего, они никогда не сравниваются ни с чем, включая себя. Также важно знать, когда что-то является строковым представлением некоторого нестрокового значения. Важно понять, какое значение видит тот уровень и что он переходит на следующий уровень. – philipxy