我有一个遗留数据库(实际上是Cobol文件),我使用Hibernate / JPA的专有JDBC驱动程序访问。
实体有一个包含2列的复合主键:CODE
和SITE
。
在旧数据中,有相同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
答案 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中不应该出现的情况做了什么。太糟糕了,他们不会在编译或执行时告诉你。希望它在文档中。)
即使find
与createQuery
不同,NULL也不足为奇。前者涉及一个值,而后者涉及预期不具有NULL的行(不是行包)(但不是行)。
解决方法可能是不将主键的任何列视为NULL,而是将其作为存储中的实际空格字符串。 (无论这意味着什么,给定您的存储/ DBMS / hibernate / JPA / Java堆栈。您还没有给我们足够的信息来了解您的Cobol数据库视图是否会因为没有为JPA将空格映射到NULL而受到阻碍)。使用您的数据,您仍然可以在列上声明UNIQUE索引。