如何将unicode数据保存到oracle?

时间:2009-07-28 06:53:33

标签: c# oracle unicode oracle10g

我正在尝试在oracle数据库(10 g)中保存unicode数据(希腊语)。我创建了一个简单的表:

alt text

据我所知,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

从消息框中的数据库获取后的文本: alt text

控制台输出: alt text

请你能在这里暗示我可能做错了吗?

6 个答案:

答案 0 :(得分:6)

我可以看到五个潜在的问题领域:

  1. 您是如何实际将文本导入.NET应用程序的?如果它在字符串文字中是硬编码的,您确定编译器是否为您的源文件采用了正确的编码吗?

  2. 您将如何将其发送到数据库时可能会出现问题。

  3. 如何将其存储在数据库中可能存在问题。

  4. 如何在数据库中提取它可能会出现问题。

  5. 之后再次显示它可能会出现问题。

  6. 现在区域2-4听起来比1和5更不容易成为问题。之后你如何显示文字?你实际上是在.NET中从数据库中取出它,还是使用Toad或类似的东西试图看到它?

    如果你再次从.NET写出来,我建议你完全跳过数据库 - 如果你只是显示字符串本身,你看到了什么?

    我有一篇文章,您可能会发现debugging Unicode problems有用。特别是,集中在编码可能出错的每个地方,并确保无论何时“显示”一个字符串,您都会转出精确的Unicode字符(作为整数),这样您就可以检查而不仅仅是你当前的字体要显示的内容。

    编辑:好的,所以数据库 涉及问题的某个地方。

    强烈建议您删除ASP和HTML之外的任何内容。编写一个简单的控制台应用程序 nothing ,但插入字符串并再次获取它。使其在之前和之后转储单个Unicode字符(作为整数)。然后尝试查看数据库中的内容(例如使用Toad)。我不知道Oracle函数将字符串转换为单个Unicode字符的序列,然后将这些字符转换为整数,但这很可能是我尝试的下一步。

    编辑:还有两个建议(很高兴看到控制台应用程序,顺便说一句)。

    1. 指定参数的数据类型,而不是仅为其指定对象。例如:

      command.Parameters.Add (":UnicodeString",
                              OracleType.NVarChar).Value = stringToSave;
      
    2. 考虑使用Oracle自己的驱动程序而不是.NET内置的驱动程序。无论如何,你可能希望这样做,因为我认为它通常被认为更快更可靠。

答案 1 :(得分:2)

您可以使用查询确定数据库对NCHAR使用的字符集:

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

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

要检查数据库配置是否正确,可以在SQL * Plus中运行以下命令:

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 Τι κάνεις;

答案 2 :(得分:1)

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

如果您使用的是oracle客户端,并希望在CommandText中包含unicode字符,则应将以下行添加到应用程序的开头:

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

如果需要,这将允许您使用以下语法:

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

答案 3 :(得分:1)

经过一些调查后我们去了:

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

答案 4 :(得分:0)

在阅读记录时,请尝试

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

答案 5 :(得分:0)

解决方案:设置NLS_LANG!

详细说明: 我遇到了同样的问题,实际上与Sergey Bazarnik的调查中描述的情况完全相同。使用绑定变量它可以工作,如果没有它,它就不会。

解决方案是将NLS_LANG设置在适当的位置。由于我有Windows服务器,我在Windows注册表下设置它 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_OraClient11g_home1

请注意,regitry位置可能不同,因此最简单的方法是在注册表中搜索&#34; ORACLE_HOME&#34;串。其他系统如Linux,Unix也可以通过不同方式设置(导出NLS_LANG ...)

就我而言,我放了"NLS_LANG"="CROATIAN_CROATIA.UTF8"。由于我没有该变量集,因此它变为默认值。 更改注册表后,您应重新启动进程。 在我的情况下,我重新启动了IIS。

关于它与绑定变量一起工作的原因可能是因为它实际上发生在服务器端,而没有它实际发生在客户端。因此,即使该DB可以插入适当的值 - 在此之前,客户端会执行不需要的更正,因为它认为应该这样做。这是因为NLS_LANG默认为更简单的代码页。但是,这不会产生有用的任务,而是会产生一个问题(如调查中所示,很难理解)。

如果您有多个oracle版本,请务必更正注册表中的所有版本(在我的情况下,Oracle 10具有有效设置,但Oracle 11根本没有设置NLS_LANG)。