Unicode转换,数据库问题(Delphi 2007到XE2)

3

目前,我正在将我们所有的Delphi 2007代码库更新到Delphi XE2。最重要的考虑因素是ANSI到Unicode的转换,我们通过重新定义所有基本类型(char/string)为ANSI类型(ansichar/ansistring)来处理这个问题。在我们的许多程序中,这已经起作用了,直到我开始与数据库一起工作。

问题始于我转换一个从文件读取信息并存储到SQL Server 2008数据库的程序。突然间,使用字符串定位数据的简单查询失败了,例如:

SELECT id FROM table WHERE name = 'something'
name字段是一个varchar类型。我发现在字符串name前面加上N前缀后,查询可以成功执行。我原本以为varchar只能存储ANSI字符,但它似乎也可以存储Unicode字符?
更多信息:Delphi中的name字段是string[13]类型,但我已尝试删除了[13]。数据库排序规则为SQL_Latin1_General_CP1_CI_AS。我们使用ADO来接口连接数据库。连接信息存储在ODBC管理器中。
注意:通过Panagiotis的指导,我已解决了实际问题。我们从映射文件中读取的名称是array[1..24] of AnsiChar类型。这个值被隐式转换为string[13]类型,其中包含空字符。因此,一个有5个字符的名称实际上被存储为5个字符+8个空字符在数据库中。
1个回答

2

varchar字段不存储Unicode字符。它们会在字段排序规则指定的代码页中存储ASCII值。当您尝试存储Unicode或来自不同代码页的数据时,SQL Server 将尝试将字符转换为正确的代码页。您可以禁用此功能,但最好的选择是在应用程序中使用nvarchar 字段和 UnicodeString 来避免混乱。

您提到在应用程序中将所有字符类型更改为 ANSI 而非 UNICODE 类型。如果要使用UNICODE,则应该使用像UnicodeString这样的UNICODE类型。否则,当发送到服务器时,您的值将被转换为ANSI。这个转换是在您创建发送到服务器的AnsiString时由您的代码完成的。

顺便说一下,您的select语句在字段中存储了一个ASCII值。如果您想将其存储为Unicode值,您必须在值前加上N,如eg.g。

SELECT id FROM table WHERE name = N'something'

即使这样也不能保证您的数据以Unicode形式到达服务器。如果您将语句存储在AnsiString中,则整个语句在发送到服务器之前会转换为ANSI。如果您的应用程序进行错误转换,则最终会在服务器上得到破碎的数据。
解决方案非常简单,只需使用参数化语句将Unicode值作为Unicode参数传递并将其存储在NVarchar字段中。它更快,避免了所有转换错误并防止SQL注入攻击。

很不幸,我能够改变的范围非常有限。我很想完全采用Unicode,但是系统的一半是使用Visual C++ 4.2编写的。我们还与一个更为复杂的系统共享一些代码,真正的Unicode转换在财务上也不可行。我会接受你所说的,并尝试更好地诊断问题发生的位置。 - Andy Clark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接