2009-12-15 39 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