从数据库读取 NVARCHAR 后,TClientDataset Widestring 字段的大小翻倍

Posted

技术标签:

【中文标题】从数据库读取 NVARCHAR 后,TClientDataset Widestring 字段的大小翻倍【英文标题】:TClientDataset Widestring field doubles in size after reading NVARCHAR from database 【发布时间】:2012-11-02 23:21:11 【问题描述】:

我正在将我们的一个 Delphi 7 项目转换为 Delphi X3,因为我们想要支持 Unicode。我们使用 MS SQL Server 2008/R2 作为我们的数据库服务器。在将一些数据库字段从 VARCHAR 更改为 NVARCHAR(并将随附的 ClientDatasets 中的字段更改为 ftWideString)后,随机崩溃开始发生。在调试时,我注意到 TClientDataset/DbExpress 的一些意外行为:

对于 NVARCHAR(10) 数据库列,我在客户端数据集中手动创建 TWideStringField 并将“Size”属性设置为 10。该字段的“DataSize”属性告诉我需要 22 个字节,这是预期的,因为 TWideStringField 的编码是UTF-16,因此每个字符需要两个字节和一些空间来存储长度。现在,当我在 ClientDataset 上调用“CreateDataset”并将数据集写入 XML(使用 .SaveToFile)时,在 XML 文件中,该字段定义为

<FIELD WIDTH="20" fieldtype="string.uni" attrname="TEST"/>

我觉得还可以。

现在,我不再调用 .CreateDataset,而是在 TClientDataset 上调用 .Open,以便它通过链接组件 ->TDatasetProvider->TSQLDataset(.CommandText = 简单的 select * from table)->TSQLConnection 获取数据。当我检查监视列表中字段的属性时,Size 仍然是 10,Datasize 仍然是 22。但是,在保存到 XML 文件后,该字段被定义为

<FIELD WIDTH="40" fieldtype="string.uni" attrname="TEST"/>

..宽度增加了一倍?

最后,如果我在 TClientDataset 上调用 .Open 而不事先创建任何字段定义,则字段的大小随后将为 20(不正确!) 和 Datasize 42。保存到 XML 后,该字段仍然定义为

<FIELD WIDTH="40" fieldtype="string.uni" attrname="TEST"/>

有人知道这里出了什么问题吗?

【问题讨论】:

您是否可能忘记调整 DatasetProvider.Dataset 中的字段? DatasetProvider.Dataset 指向一个 TSQLDataset,我在这个 TSQLDataset 中根本没有任何字段/字段定义。 为了测试,我将 TSQLDataset 的 CommandMode 从 ctQuery 更改为 ctTable 并让设计人员检索导致相同错误结果的字段定义:大小为 20 的 TWideStringField。 1)您是否清理了所有 DCU 并确保从头开始重建? 2) 您是否使用从组件面板中弹出的组件?只是一种预感,但如果是这样,也许您需要删除它们,重新放置新的,然后删除所有输出并从头开始重建。 【参考方案1】:

在 SQLCommand 组件(在 DatasetProvider 之前)检查字段类型及其大小。

大小加倍可能是两个隐式“转换”的结果:首先 - 服务器提供 NVarchar 数据,该数据存储在 ansi-string 字段中(每个字节都成为一个单独的字符),其次 - 它存储在 clientdataset 的类型字段中宽字符串,每个字符变成 2 个字节(大小加倍)。

请注意,在先前版本的 Delphi 中,ClientDataset 的字段与相应的 Query/Command 字段之间的字符串字段大小不匹配不会导致异常,但从 XE* 之一开始,它通常会导致 AV。所以在迁移过程中你必须仔细检查字符串字段的大小。

【讨论】:

【参考方案2】:

听起来好像是因为列数据类型发生了变化,这给您带来了意想不到的问题。我的建议是 1.备份表,多种方法,比喻挑毒 2.删除表, 3.重新创建表, 4. 将旧表中的数据导入到新创建的表中。看看是否有帮助。

当列数据类型发生变化时,Sql 表不喜欢它,这样做可能会出现意想不到的问题。所以尝试一下,在最坏的情况下,你可能浪费了十分钟的时间来尝试一个可能的解决方案。

【讨论】:

以上是关于从数据库读取 NVARCHAR 后,TClientDataset Widestring 字段的大小翻倍的主要内容,如果未能解决你的问题,请参考以下文章

从 SQL Server 读取 XML

python读取数据库中文乱码问题

sqlserver2008 字符串类型varchar,nvarchar,nchar之间的区别

将 nvarchar 转换为日期时间/日期后的计算

如何使用 SQLAPI++ 从 SQL 服务器读取 unicode 字符?

如何从文本 (NVARCHAR(MAX)) 列中提取一个或多个 URL