JPA查询返回空值 - 具有空列

时间:2015-12-04 01:41:22

标签: java sql hibernate jpa composite-primary-key

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

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

在旧数据中,有相同CODE的记录可以具有SITE的特定值,或者SITE列中可能有一个带有NULL的记录'所有网站'。该文件的理论是,如果找不到特定CODE的{​​{1}},那么在SITE('catch-all')中查找带有NULL的记录。

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

现在,当我使用包含特定SITE的主复合键类和em.find的空值执行code时,Hibernate会正确地找到匹配记录中的NULL值专栏 - 一切都好!

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

em.createQuery

有2条记录,它在SELECT x FROM TareWeight x WHERE x.pk.code = 'LC2' 列中的NULL记录的结果列表中返回一个空对象。

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

所以要么Hibernate支持它,要么它不支持它。为什么SITE有效,而em.find

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

编辑:好的,所以我在this Hibernate JIRA Issue上找到了em.createQuery类定义并将其添加到我的项目中。

如果我使用此类型类在PK的NullableStringType列上添加@Type定义,那么我可以使用{{1}成功从SELECT查询中获取非空实体}字段包含我定义为site的表示的任何字符串文本。

然而,它仍然表现不同。 site返回包含null的{​​{1}}字段的实体,但查询返回包含“NaN”find字段的实体(默认表示为{{1} }})。

仍然觉得这些应该表现得一样。

更新2:有些人想知道有关“数据库”的具体信息。

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

我们将配置设置为将空白(SPACES)字母数字字段转换为NULL,因此包含PK字段空格的文件记录将被转换为NULL。我可以使用site专门选择适当的记录,因此RDBMS 将这些空白字段视为SQL NULL。

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

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

以下是查找的SQL:

site

这是查询的SQL:

null

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

更新3:以下是一些示例数据:

WHERE site_id IS NULL

专门搜索NULL:

find

1 个答案:

答案 0 :(得分:8)

  

"所以要么他们支持它,要么他们没有"

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

以下是Hibernate Team回答的(旧的)支持主题:

发布主题:一列为空值的复合键
PostPosted:2006年7月3日星期一凌晨2:21

  

我有复合主键表,我创建了以下内容   表的映射。因为可以为any插入空值   复合键中的列只要是所有列的组合即可   唯一的,我在表中记录了V_CHAR2的空值   列(复合键的一部分)。当我执行查询时   这个实体我获得了null的记录的空值   V_CHAR2列的值。我的映射和错误有什么问题   实施..

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

  

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

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

  

抱歉让您失望,但不支持主键为空 -   主要是因为进行连接和比较将需要很多   在其他任何地方都不需要的痛苦愚蠢的代码.....想想   关于它,你会看到(例如你如何做正确的加入   这样的表)

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

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

解决方法可能是不将主键的任何列视为NULL,而是将其作为存储中的实际空格字符串。 (无论这意味着什么,给定您的存储/ DBMS / hibernate / JPA / Java堆栈。您还没有给我们足够的信息来了解您的Cobol数据库视图是否会因为没有为JPA将空格映射到NULL而受到阻碍)。使用您的数据,您仍然可以在列上声明UNIQUE索引。

相关问题