2009-12-15 45 views
3

我在Oracle中使用Hibernate和char(6)列有点麻烦。下面是表的结构:在Oracle的CHAR主键列上休眠和填充

CREATE TABLE ACCEPTANCE 
(
    USER_ID char(6) PRIMARY KEY NOT NULL, 
    ACCEPT_DATE date 
); 

对于其用户ID具有少于6个字符的记录,我可以选择它们而不使用SQuirreL运行查询时填充的用户ID。 I.E.如果有一个用户标识为“abc”的记录,则返回记录。

select * from acceptance where user_id = "abc" 

不幸的是,通过休眠(JPA)在做选择的时候,下面的返回null:

em.find(Acceptance.class, "abc"); 

如果我垫的价值,虽然,它返回正确的记录:

em.find(Acceptance.class, "abc "); 

我正在处理的模块从系统的其他部分获取用户标识未加注释。有没有更好的方式让Hibernate工作,而不是在将代码提供给Hibernate之前将代码调整为一定的长度以外的代码? (如果长度有变化,可能会出现维修问题)

+0

“如果长度过变化。”如果发生这种情况,您的主键会发生变化,您会发现很多问题需要担心。 – 2009-12-15 23:41:38

回答

3

也就是说,是上帝的告诉你从不使用CHAR()用于主键:-)

认真的方式,但是因为你的user_id被映射为字符串在实体Hibernate的甲骨文方言转换到这varchar。由于Hibernate为所有查询使用准备好的语句,这个语义继承了(不同于SQuirreL,其中值被指定为文字并因此被不同地转换)。

基于Oracle type conversion rules的列值然后被提升为varchar2并进行比较;因此你没有收到任何记录。

如果不能更改底层的列类型,最好的选择是使用Oracle语言支持的HQL查询和rtrim()函数。

+0

我想过做一些像em.createQuery(“来自接受其中trim(userId)=:userId”);但会否击败主键上的索引? – jthg 2009-12-15 19:34:02

+0

您只需要'rtrim()',而不是完整的'trim()',并且应该仍然使用非空白字符的索引。 – ChssPly76 2009-12-15 19:37:30

+0

你确定吗?我在Google上发现了一些论坛帖子,说rtrim _does_会导致表扫描。 – jthg 2009-12-15 19:43:42

0

我不这么认为。不过,您可以定义一个UserType来包含一个点的损坏。

1

为什么你的模块从系统的其他部分获得未填充的值?根据我的理解,如果系统的其他部分不改变PK,他们应该从数据库中读取6个字符并传递6个字符 - 这样可以。唯一的例外是在生成PK时,在这种情况下可能需要填充。

您可以规避问题(每次修改或填充值时都需要修改或填充值),但它不能一直解决您的PK未处理的问题。为了解决这个问题的前期必须eiher

  • 总是收到来自模块
  • 使用varchar2的其他部分6个字符处理动态尺寸正确

如果你能不能解决问题前期,那么你的确需要或者

  • 加修剪/填充各地的地方,必要时
  • 添加在DAO修剪/填充,如果你有用户类型一个
  • 加修剪/填充,如果这个工程(建议从N.休斯)
+0

我甚至会说,如果数据库类型是一个CHAR(6),那么它语义上期望该数据库的客户使用6个字符,句点的例子。所以要么DB定义必须改变,要么客户需要遵守:) – Romain 2009-12-15 19:56:52