2009-07-28 105 views
6

我試圖在oracle數據庫(10克)中保存unicode數據(希臘語)。我創建了一個簡單的表:如何將unicode數據保存到oracle?

alt text http://i25.tinypic.com/dvpqnk.png

我明白,NVARCHAR2總是使用UTF-16編碼所以它必須是罰款所有(人)語言。

然後我試圖在數據庫中插入一個字符串。我用代碼硬編碼了字符串(「你好嗎?」,希臘語)。然後我嘗試從數據庫中取回並顯示它。

class Program 
{ 
    static string connectionString = "<my connection string>"; 

    static void Main (string[] args) { 
     string textBefore = "Τι κάνεις;"; 

     DeleteAll(); 
     SaveToDatabase (textBefore); 
     string textAfter = GetFromDatabase(); 

     string beforeData = String.Format ("Before: {0}, ({1})", textBefore, ToHex (textBefore)); 
     string afterData = String.Format ("After: {0}, ({1})", textAfter, ToHex (textAfter)); 

     Console.WriteLine (beforeData); 
     Console.WriteLine (afterData); 

     MessageBox.Show (beforeData); 
     MessageBox.Show (afterData); 

     Console.ReadLine(); 
    } 

    static void DeleteAll() { 
     using (var oraConnection = new OracleConnection (connectionString)) { 
      oraConnection.Open(); 
      var command = oraConnection.CreateCommand(); 

      command.CommandText = "delete from UNICODEDATA"; 
      command.ExecuteNonQuery(); 
     }    
    } 

    static void SaveToDatabase (string stringToSave) { 
     using (var oraConnection = new OracleConnection (connectionString)) { 
      oraConnection.Open(); 
      var command = oraConnection.CreateCommand(); 

      command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, :UnicodeString)"; 
      command.Parameters.Add (":UnicodeString", stringToSave); 
      command.ExecuteNonQuery(); 
     } 
    } 

    static string GetFromDatabase() { 
     using (var oraConnection = new OracleConnection (connectionString)) { 
      oraConnection.Open(); 

      var command = oraConnection.CreateCommand(); 
      command.CommandText = "Select * from UNICODEDATA"; 
      var erpReader = command.ExecuteReader(); 

      string s = String.Empty; 
      while (erpReader.Read()) { 
       string text = erpReader.GetString (1); 
       s += text + ", "; 
      } 

      return s; 
     } 
    } 

    static string ToHex (string input) { 
     string bytes = String.Empty; 
     foreach (var c in input) 
      bytes += ((int)c).ToString ("X4") + " "; 

     return bytes; 
    } 
} 

這裏有不同的輸出: alt text http://i28.tinypic.com/2wmq9a0.png

控制檯輸出:在消息框中從數據庫中獲取之後 alt text http://i31.tinypic.com/2ymdo2u.png

文本:在消息框中發送到數據庫之前

文本: alt text http://i29.tinypic.com/6xz3px.png

請你可以建議我可能在這裏做錯了嗎?

回答

5

我可以看到五個潛在領域的問題:

  1. 你是如何真正去文成.NET應用程序?如果它在字符串文字中被硬編碼,你確定編譯器是否爲你的源文件採用了正確的編碼?

  2. 如何將它發送到數據庫可能存在問題。

  3. 存儲在數據庫中可能存在問題。

  4. 如何在數據庫中獲取數據可能存在問題。

  5. 之後您可能會再次顯示問題。

現在2-4區聽起來像他們不太可能成爲一個問題比1和5.你以後如何顯示文本?你真的在.NET中將它從數據庫中提取出來,或者你是否在使用Toad或類似的東西來嘗試查看它?

如果你從.NET再次寫出它,我建議你完全跳過數據庫 - 如果你只是顯示字符串本身,你看到了什麼?

我有一篇文章可能對debugging Unicode problems有用。尤其要注意編碼的每個地方都會出錯,並確保每當你「顯示」一個字符串時,你都會輸出確切的Unicode字符(作爲整數),這樣你就可以檢查這些字符而不僅僅是當前的字體想顯示。

編輯:好的,所以數據庫涉及問題的某處。

強烈建議您刪除ASP和HTML之外的任何東西。寫一個簡單的控制檯應用程序,沒有但插入字符串並再次獲取它。使它在前後轉儲單個Unicode字符(作爲整數)。然後嘗試查看數據庫中的內容(例如使用Toad)。我不知道Oracle函數將字符串轉換爲單個Unicode字符序列,然後將這些字符轉換爲整數,但這很可能是我嘗試的下一件事。

編輯:兩個更多的建議(很高興看到控制檯應用程序,順便說一句)。

  1. 指定參數的數據類型,而不是隻給它一個對象。例如:

    command.Parameters.Add (":UnicodeString", 
             OracleType.NVarChar).Value = stringToSave; 
    
  2. 考慮使用甲骨文自己的驅動程序,而不是一個內置到.NET的。無論如何,你可能希望這樣做,因爲我相信它通常被認爲更快,更可靠。

+0

如果我跳過數據庫並直接顯示字符串,它會正確顯示希臘字符串。我已經更新了關於如何從數據庫中獲取數據的問題。請你可以投入更多的光線嗎? – Hemant 2009-07-28 07:18:05

+0

需要注意的另一件事是,如果我使用SQL Server Express版本並執行相同的操作(替換Linq查詢插入和獲取數據的代碼),它會正確顯示字符串。 – Hemant 2009-07-28 07:22:23

+0

Jon:我已經更新了這個問題(包含控制檯應用程序中的代碼)。它的奇怪,控制檯輸出也擰,但消息框顯示正確... – Hemant 2009-07-28 08:14:20

2

您可以確定哪些字符集,您的數據庫使用的NCHAR與查詢:

SQL> SELECT VALUE 
    2 FROM nls_database_parameters 
    3 WHERE parameter = 'NLS_NCHAR_CHARACTERSET'; 

VALUE 
------------ 
AL16UTF16 

檢查,如果你的數據庫配置是正確的,你可以運行在SQL以下*加:

SQL> CREATE TABLE unicodedata (ID NUMBER, unicodestring NVARCHAR2(100)); 

Table created 
SQL> INSERT INTO unicodedata VALUES (11, 'Τι κάνεις;'); 

1 row inserted 
SQL> SELECT * FROM unicodedata; 

     ID UNICODESTRING 
---------- --------------------------------------------------- 
     11 Τι κάνεις; 
1

還有一件值得注意的事情。

如果您正在使用Oracle客戶端,並希望包括在CommandText Unicode字符,你應該folloing行添加到您的應用程序的啓動:

System.Environment.SetEnvironmentVariable("ORA_NCHAR_LITERAL_REPLACE", "TRUE"); 

這將使你的,萬一你需要的時候,使用的語法如下:

command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, N'Τι κάνεις;')"; 
0

在閱讀記錄,嘗試

Encoding utf = Encoding.Default; 
var utfBytes = odatareader.GetOracleString(0).GetNonUnicodeBytes();//OracleDataReader 
Console.WriteLine(utf.GetString(utfBytes)); 
0

我們經過一番調查後發現:

string input =「•」; char s = input [0];

 //table kuuku with column kuku(nvarchar2(100)) 
     string connString = "your connection"; 

     //CLEAN TABLE 
     using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) 
     { 
      cn.Open(); 
      System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("delete from kuku ", cn); 
      cmd.ExecuteNonQuery(); 
      cn.Close(); 
     } 


     //INSERT WITH PARAMETER BINDING - UNICODE SAVED 
     using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) 
     { 
      cn.Open(); 
      System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values(:UnicodeString)", cn); 
      cmd.Parameters.Add(":UnicodeString", System.Data.OracleClient.OracleType.NVarChar).Value = input + " OK" ; 
      cmd.ExecuteNonQuery(); 
      cn.Close(); 
     } 

     //INSERT WITHOUT PARAMETER BINDING - UNICODE NOT SAVED 
     using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) 
     { 
      cn.Open(); 
      System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values('" +input+" WRONG')", cn); 
      cmd.ExecuteNonQuery(); 
      cn.Close(); 
     } 
     //FETCH RESULT 
     using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) 
     { 
      cn.Open(); 
      System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("select kuku from kuku", cn); 
      System.Data.OracleClient.OracleDataReader dr = cmd.ExecuteReader(); 
      if(dr.Read()) 
      { 
       string output = (string) dr[0]; 
       char sa = output[0]; 
      } 
      cn.Close(); 
     } 
    } 

PL SQL look

0

解決方案:設置NLS_LANG!

詳情: 我剛剛遇到了同樣的問題,實際上的確有與Sergey Bazarnik調查中描述的相同的情況。它使用綁定變量,沒有它,它不會。

解決方法是在適當的位置設置NLS_LANG。因爲我有Windows服務器我將它設置在Windows註冊表 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_OraClient11g_home1

下請注意,regitry位置可能difer所以最簡單的方法是搜索註冊表「ORACLE_HOME」字符串。另外像Linux,Unix等系統可以以不同的方式設置它(導出NLS_LANG ...)

在我的情況下,我把"NLS_LANG"="CROATIAN_CROATIA.UTF8"。由於我沒有這個變量集,它變成了默認值。 更改註冊表後,您應該重新啓動進程。 在我的情況下,我重新啓動IIS。

關於它與綁定變量一起工作的原因可能是因爲它實際上發生在服務器端,而沒有實際發生在客戶端。因此,即使DB可以插入適當的值 - 在發生這種情況之前,客戶端會執行不需要的更正,因爲它認爲應該這樣做。這是因爲NLS_LANG默認爲更簡單的代碼頁。但不是做有用的工作,而是產生一個問題,(如調查顯示,很難理解)。

如果您有多個oracle版本,一定要更正註冊表中的所有版本(在我的情況下Oracle 10有效設置,但Oracle 11根本沒有設置NLS_LANG)。