I have a legacy database (Cobol files actually) that I am accessing using a proprietary JDBC driver with Hibernate/JPA.
The Entity has a composite primary key with 2 columns: CODE
and SITE
.
In the legacy data there are records for the same CODE
that can have either a specific value for SITE
, or there can be a record with NULL in the SITE
column which represents 'All Sites'. The theory of this file is, if you cannot find the CODE
for your specific SITE
then you lookup the record with NULL in the SITE
(the 'catch-all').
I cannot change the structure of this 'table' as it would involve rewriting large parts of the legacy Cobol system which we don't want to do. I also cannot create views of the data.
Now when I do an em.find
with the primary composite key class containing a specific code
and a null for site
, then Hibernate correctly finds the matching record with the NULL value in the column - All good!
But if I try to do a query using em.createQuery
similar to the following:
SELECT x FROM TareWeight x WHERE x.pk.code = 'LC2'
for which there are 2 records, it returns a null object in the resulting list for the record with the NULL in the SITE
column.
If I take the SQL that Hibernate uses for this query, then the 'database' returns two records, one with the NULL site and one with a specific site. It seems that when Hibernate loads the Entities from these results, it is mapping it to a null Entity object.
So either Hibernate supports it or it doesn't. Why would the em.find
work but not the em.createQuery
?
I know that this question is similar, but the answers seem to suggest that it is impossible. But clearly Hibernate can do the find correctly, so why does the query not work?
EDIT: OK, so I found a NullableStringType
class definition on this Hibernate JIRA Issue and added it to my project.
If I add a @Type
definition on the site
column of the PK using this type class, then I can successfully get non-null Entities back from the SELECT query, with the site
field containing whatever String text I define as the representation of null
.
However, it is still behaving differently. The find
returns an Entity with the site
field containing null
, but the query returns an Entity with the site
field containing "NaN" (the default representation of null
).
It still feels like these should behave the same.
UPDATE 2: Some of you want to know specifics about the 'database' in question.
It is the Genesis RDBMS engine, written by Trifox Inc.. The data is stored in AcuCobol (now Micro Focus) Vision indexed files.
We have the configuration set to translate blank (SPACES) alphanumeric fields to NULL, hence our file records which contain spaces for the PK field are being translated to NULL. I can specifically select the appropriate record by using WHERE site_id IS NULL
, so the RDBMS is treating these blank fields as an SQL NULL.
Having said all that I do not believe that this issue has anything to do with the 'database', apart from the fact that it is unusual to have PK fields being null.
What's more, if I log the SQL that Hibernate is using for both the find
and the query, they are almost identical.
Here's the SQL for the find:
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=?
And here's the SQL for the Query:
select tareweight0_.CODE as CODE274_, tareweight0_.SITE as SITE274_,
tareweight0_.WEIGHT as WEIGHT274_ from TARE_WEIGHT tareweight0_
where tareweight0_.CODE=? and tareweight0_.SITE=?
As you can see, the only difference is the column alias names.
UPDATE 3: Here's some example data:
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
And searching specifically for 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