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

Dun*_*ear 10 java sql hibernate jpa composite-primary-key

我有一个遗留数据库(实际上是Cobol文件),我使用Hibernate/JPA的专有JDBC驱动程序访问.

实体有一个包含2列的复合主键:CODESITE.

在传统的数据存在针对相同的记录CODE是可以有一个特定的值SITE,或者可以有与空记录SITE柱代表"所有网站".这个文件的理论是,如果你找不到CODE特定的,SITE那么你在SITE('catch-all')中查找带有NULL的记录.

我不能改变这个'表'的结构,因为它将涉及重写我们不想做的传统Cobol系统的大部分.我也无法创建数据视图.

现在,当我em.find使用包含特定code和null 的主复合键类时site,Hibernate正确地在列中找到具有NULL值的匹配记录 - 一切都好!

但是,如果我尝试使用em.createQuery类似于以下内容进行查询:

SELECT x FROM TareWeight x WHERE x.pk.code = 'LC2'
Run Code Online (Sandbox Code Playgroud)

如果有2条记录,它会在结果列表中为SITE列中的NULL返回一个空对象.

如果我使用Hibernate用于此查询的SQL,那么'database'将返回两条记录,一条记录具有NULL站点,另一条记录具有特定站点.似乎当Hibernate从这些结果加载实体时,它将它映射到空Entity对象.

所以要么Hibernate支持它,要么它不支持它.为什么em.find工作而不是em.createQuery

我知道这个问题很相似,但答案似乎表明这是不可能的.但显然Hibernate可以正确地进行查找,那么为什么查询不起作用呢?


编辑:好的,所以我NullableStringType这个Hibernate JIRA问题上找到了一个类定义,并将它添加到我的项目中.

如果我使用这个类型类在PK @Typesite列上添加一个定义,那么我可以成功地从SELECT查询中获取非空实体,该site字段包含我定义的任何String文本作为其表示null.

但是,它仍然表现不同.所述find返回一个实体与所述site字段包含null,但该查询返回的实体与site包含"南"(的默认表示字段null).

它仍然感觉这些应该表现相同.


更新2:有些人想知道有关"数据库"的具体细节.

它是Genesis RDBMS引擎,由Trifox Inc.编写.数据存储在AcuCobol(现为Micro Focus)Vision索引文件中.

我们将配置集设置为将空白(SPACES)字母数字字段转换为NULL,因此包含PK字段空格的文件记录将被转换为NULL.我可以通过使用专门选择相应的记录WHERE site_id IS NULL,所以RDBMS 治疗这些空白字段作为SQL NULL.

说完所有我不相信这个问题与'数据库'有关,除了PK字段为空是不寻常的事实.

更重要的是,如果我记录Hibernate用于find查询和查询的SQL,它们几乎完全相同.

这是查找的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=?
Run Code Online (Sandbox Code Playgroud)

这是查询的SQL:

select tareweight0_.CODE as CODE274_, tareweight0_.SITE as SITE274_, 
       tareweight0_.WEIGHT as WEIGHT274_ from TARE_WEIGHT tareweight0_ 
       where tareweight0_.CODE=? and tareweight0_.SITE=?
Run Code Online (Sandbox Code Playgroud)

如您所见,唯一的区别是列别名.


更新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
Run Code Online (Sandbox Code Playgroud)

并专门搜索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
Run Code Online (Sandbox Code Playgroud)

phi*_*pxy 8

"所以要么他们支持,要么他们不支持"

TL; DR那种期望/感觉是没有道理的.您链接(以及我的下方)中不受支持的功能正是您的."不支持"意味着如果你这样做,那么Hibernate可以做任何他们想做的事情.你很幸运他们(似乎)回归了合理的价值观.(虽然只是猜测他们是如何行动的.你没有规范.)没有理由期待任何事情,更不用说一致性了.当行为只是一些不受支持的案例产生的结果时,任何"为什么"很可能只是一个关于代码是如何编写其他案例的工件.


这是Hibernate团队回答的(旧的)支持线程:

发布主题:一
列为空值的复合键PostPosted:Mon Jul 03,2006 2:21 am

我有复合主键的表,我为表创建了以下映射.因为只要所有列的组合都是唯一的,就可以为复合键中的任何列插入空值,我在表中有记录V_CHAR2列的空值(它是复合键的一部分).当我对这个实体执行查询时,我得到具有空值V_CHAR2列的记录的空值.我的映射和实现有什么问题..

发布时间:2006年7月11日星期二上午9:09
Hibernate Team

主键不能为空(既不完全也不是部分)

发布时间:2007年1月6日星期六上午5:35
Hibernate Team

抱歉disapoint你,但在主键无效,不支持-主要是因为这样做加盟的和比较需要的,这只是不需要其他任何地方painfullly愚蠢的代码很多.....仔细想想,你会看到(例如,你怎么了用这样的表做正确的连接)

这并不奇怪,因为SQL中的PK列不允许使用NULL.PRIMARY KEY声明是UNIQUE NOT NULL的同义词.NULL不等于具有(误导)意图的任何事物,即未知某些未记录的值是相等的.(你的某种异常的至少一些在PK NULL场合的预期等于在条件NULL是违背SQL)由于NULL不PK值允许,我们可以期待与1 PK优化:1映射和设置而不是行包以假设在方便的时候没有NULL.可以预料的是,Hibernate决定不担心它们的实现对SQL中不应出现的情况的影响.太糟糕了,他们没有告诉你编译或执行.希望它在文档中.)

即使findcreateQueryre NULL 不同也不足为奇.前者涉及一个值,而后者涉及预期不具有NULL(但不是)的行集(不是行包).

解决方法可能是不将主键的任何列视为NULL,而是将其作为存储中的实际空格字符串.(不管这意味着给您的存储/ DBMS /休眠/ JPA/Java堆栈.你没有给我们足够的信息来了解数据库是否你Cobol语言的观点由于没有映射空间为NULL您的JPA受到阻碍).使用您的数据,您仍然可以在列上声明UNIQUE索引.