3

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

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

SELECT id FROM table WHERE name = 'something'

name字段是一个varchar. 我发现我可以通过在字符串名称前加上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 个空字符存储在数据库中的。

4

1 回答 1

2

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

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

顺便说一句,您的 select 语句在字段中存储一个 ASCII 值。如果要将其存储为 unicode 值,则必须在该值前面加上 N,例如

SELECT id FROM table WHERE name = N'something'

即使这样也不能保证您的数据将以 Unicode 格式到达服务器。如果将语句存储在 AnsiString 中,则整个语句在发送到服务器之前将转换为 ANSI。如果您的应用程序进行了错误的转换,您最终会在服务器上得到损坏的数据。

解决方案很简单,只需使用参数化语句将 unicode 值作为 unicode 参数传递并存储在 NVarchar 字段中。它速度更快,避免了所有转换错误并防止 SQL 注入攻击。

于 2012-05-11T13:42:20.487 回答