简体   繁体   English

JPA Query返回空值 - 具有空列的Composite Key

[英]JPA Query returning nulls - Composite Key with null column

I have a legacy database (Cobol files actually) that I am accessing using a proprietary JDBC driver with Hibernate/JPA. 我有一个遗留数据库(实际上是Cobol文件),我使用Hibernate / JPA的专有JDBC驱动程序访问。

The Entity has a composite primary key with 2 columns: CODE and SITE . 实体具有一个包含2列的复合主键: CODESITE

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'. 在遗留数据中,存在可以具有SITE特定值的相同CODE记录,或者在SITE列中可以存在具有NULL的记录,其表示“所有站点”。 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'). 该文件的理论是,如果你不能找到CODE为您的特定SITE ,那么你查找的记录中,NULL SITE (在“包罗万象”)。

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. 我不能改变这个'表'的结构,因为它将涉及重写我们不想做的传统Cobol系统的大部分。 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! 现在,当我使用包含特定codesite空值的主复合键类执行em.find时,Hibernate正确地在列中找到具有NULL值的匹配记录 - 一切都很好!

But if I try to do a query using em.createQuery similar to the following: 但是,如果我尝试使用类似于以下内容的em.createQuery进行查询:

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. 如果有2条记录,它会在结果列表中为SITE列中的NULL返回一个空对象。

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. 如果我使用Hibernate用于此查询的SQL,那么'database'将返回两条记录,一条记录具有NULL站点,另一条记录具有特定站点。 It seems that when Hibernate loads the Entities from these results, it is mapping it to a null Entity object. 似乎当Hibernate从这些结果加载实体时,它将它映射到空Entity对象。

So either Hibernate supports it or it doesn't. 所以要么Hibernate支持它,要么它不支持它。 Why would the em.find work but not the em.createQuery ? 为什么em.find工作但不是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? 但显然Hibernate可以正确地进行查找,那为什么查询不起作用呢?


EDIT: OK, so I found a NullableStringType class definition on this Hibernate JIRA Issue and added it to my project. 编辑:好的,所以我在这个Hibernate JIRA问题上找到了一个NullableStringType类定义,并将它添加到我的项目中。

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 . 如果我使用此类型类在PK的site列上添加@Type定义,那么我可以从SELECT查询成功获取非空实体,其中site字段包含我定义的任何String文本作为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 ). find返回一个Entity,其site字段包含null ,但查询返回一个Entity,其site字段包含“NaN”(默认表示为null )。

It still feels like these should behave the same. 它仍然感觉这些应该表现相同。


UPDATE 2: Some of you want to know specifics about the 'database' in question. 更新2:有些人想知道有关“数据库”的具体细节。

It is the Genesis RDBMS engine, written by Trifox Inc. . 它是Genesis RDBMS引擎,由Trifox Inc.编写。 The data is stored in AcuCobol (now Micro Focus) Vision indexed files. 数据存储在AcuCobol(现为Micro Focus)Vision索引文件中。

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. 我们将配置集设置为将空白(SPACES)字母数字字段转换为NULL,因此包含PK字段空格的文件记录将被转换为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. 我可以通过使用专门选择适当的记录WHERE site_id IS NULL ,所以RDBMS 治疗这些空白字段作为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. 说完所有我不相信这个问题与'数据库'有关,除了PK字段为空是不寻常的事实。

What's more, if I log the SQL that Hibernate is using for both the find and the query, they are almost identical. 更重要的是,如果我记录Hibernate用于find和查询的SQL,它们几乎完全相同。

Here's the SQL for the 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=?

And here's the SQL for the Query: 这是查询的SQL:

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: 更新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

And searching specifically for NULL: 并专门搜索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

"So either they support it or they don't" “所以要么他们支持,要么他们不支持”

TL;DR That expectation/feeling is unjustified. TL; DR那种期望/感觉是没有道理的。 The unsupported functionality in your link (& mine below) is exactly yours. 您链接(以及我的下方)中不受支持的功能正是您的。 "Not supporting" it means that if you do it then Hibernate can do anything they want. “不支持”意味着如果你这样做,那么Hibernate可以做任何他们想做的事情。 You are lucky that they (seem to) return reasonable values. 你很幸运他们(似乎)回归了合理的价值观。 (Although it's just a guess how they are acting. You don't have a specification.) There is no reason to expect anything, let alone consistency. (虽然只是猜测他们是如何行动的。你没有规范。)没有理由期待任何事情,更不用说一致性了。 When behaviour is just a consequence of some unsupported case arising, any "why" is most likely just an artifact of how the code was written with other cases in mind. 当行为只是一些不受支持的案例产生的结果时,任何“为什么”很可能只是一个关于代码是如何编写其他案例的工件。


Here is a(n old) support thread answered by the Hibernate Team : 这是Hibernate团队回答的(旧的)支持线程:

Post subject: Composite key with null value for one column 发布主题:一列为空值的复合键
PostPosted: Mon Jul 03, 2006 2:21 am PostPosted:2006年7月3日星期一凌晨2:21

I have table with composite primary key and I created following mapping for the table.As it is possible to insert a null value for any column in composite key as long as the combination of all columns is Unique, I have record in teh table which has null value for V_CHAR2 column ( which is part of composite key ) . 我有复合主键的表,我为表创建了以下映射。因为只要所有列的组合都是唯一的,就可以为复合键中的任何列插入空值,我在表中有记录V_CHAR2列的空值(它是复合键的一部分)。 when I execute a query on this entity I get null values for the records which are having null value of V_CHAR2 column. 当我对这个实体执行查询时,我得到具有空值V_CHAR2列的记录的空值。 What's wrong in my mapping and implementation.. 我的映射和实现有什么问题..

Posted: Tue Jul 11, 2006 9:09 am 发布时间:2006年7月11日星期二上午9:09
Hibernate Team Hibernate团队

a primary key cannot be null (neither fully or partial) 主键不能为空(既不完全也不是部分)

Posted: Sat Jan 06, 2007 5:35 am 发布时间:2007年1月6日星期六上午5:35
Hibernate Team Hibernate团队

sorry to disapoint you but null in primary key is not supported - primarily because doing join's and comparisons will require alot of painfullly stupid code that is just not needed anywhere else.....think about it and you will see (eg how do you do a correct join with such a table) 很抱歉让你失望,但不支持主键中的null - 主要是因为进行连接和比较将需要很多其他地方不需要的痛苦愚蠢的代码.....想想它,你会看到(例如你怎么做用这样的表做正确的连接)

This is not surprising, because NULL is not allowed in a PK column in SQL. 这并不奇怪,因为SQL中的PK列不允许使用NULL。 A PRIMARY KEY declaration is a synonym for UNIQUE NOT NULL. PRIMARY KEY声明是UNIQUE NOT NULL的同义词。 NULL is not equal to anything with the (misguided) intent that some unrecorded value is not known to be equal. NULL不等于具有(误导)意图的任何事物,即未知某些未记录的值是相等的。 (Your expectations of some kind of exception for at least some occasions of NULL in a PK equaling a NULL in a condition is contrary to SQL.) Given that NULL is not allowed in PK values, we can expect PK optimizations related to 1:1 mappings and to sets rather than bags of rows to assume there are no NULLs when it's convenient. (你的某种异常的至少一些在PK 等于在条件NULL NULL场合的预期是相反的SQL。)鉴于NULL不PK值允许,我们可以期待与1 PK优化:1映射和设置而不是行包以假设在方便的时候没有NULL。 One can expect that Hibernate decided to not worry about what their implementation did with cases that shouldn't arise in the SQL. 可以预料的是,Hibernate决定不担心它们的实现对SQL中不应出现的情况的影响。 Too bad they don't tell you that on compilation or execution. 太糟糕了,他们没有告诉你编译或执行。 Hopefully it is in documentation.) 希望它在文档中。)

Even find differing from createQuery re NULL is not surprising. 即使findcreateQuery不同, createQuery也不奇怪。 The former involves one value while the latter involves what are expected to be sets (not bags) of rows without NULLs (but aren't). 前者涉及一个值,而后者涉及预期不具有NULL(但不是)的行集(不是行包)。

A workaround may be to not treat any column of a primary key as NULL but as the actual string of spaces in storage. 解决方法可能是不将主键的任何列视为NULL,而是将其作为存储中的实际空格字符串。 (Whatever this means given your storage/DBMS/hibernate/JPA/Java stack. You haven't given us enough information to know whether your Cobol view of the database would be impeded by not mapping spaces to NULL for your JPA). (无论这给你的存储/ DBMS / hibernate / JPA / Java堆栈意味着什么。你还没有给我们足够的信息来知道你的Cobol数据库视图是否会因为你的JPA没有将空格映射到NULL而受阻。 With your data you can still declare a UNIQUE index on the columns. 使用您的数据,您仍然可以在列上声明UNIQUE索引。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM