2009-07-28 57 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)。