Delphi TADOQuery.next 跳过一条记录
Delphi TADOQuery.next skipping a record
application/processing
的说明
我正在 Delphi XE 中维护一些旧代码。该应用程序对远程服务器上的数据库运行查询,然后在 PC 上创建报告。我们有一个错误报告,其中一个字段中的某些数据丢失。有问题的字段包含从服务器收集的大量数据(几千个字符)。我无法控制该字段中收集和存储的数据。我发现该错误是由该数据中嵌入的空值和其他控制字符(换行符等)引起的。当调用 TADOQuery 的 SaveToFile 方法时,空值和其他控制字符导致字段中稍后的任何数据被忽略(SaveToFile 基本上到达控制字符并停止读取记录)。
该错误的解决方案是从结果集中提取有问题的字段,过滤掉所有控制字符并将其保存到临时文件(此时我无法将其放回结果集中,因为它处于只读状态)。数据保存为 XML 所以我还必须使一些字符 XML 友好(正如您将在代码片段中看到的那样)。调用 SaveToFile 方法后,我将从临时文件中读取更正后的数据并将其写回到已保存的报告中。它冗长但有效。
问题
我现在有一个新问题。我注意到在随机情况下,文件末尾会丢失一条记录(相关字段为空白)。我花了很长时间来研究这个问题,它归结为以下代码(用于在调用 SaveToFile 之前从字段中提取数据)。该代码正在跳过一行。不是每次——大约每两到三个查询运行中就有一个。我知道这是事实,因为我在调试时在下面的循环中添加了一个计数器,并将循环执行的次数与记录计数进行了比较,并且在发生错误时它返回的次数少了一个(导致空白字段)并且当所有数据都出现在报告中时相等。没有捕获到任何异常,因此它不会跌倒在某些东西上 - 它实际上是在跳过一条记录。
assignfile(f, tempFilename);
rewrite(f);
adoqry.first;
repeat
try
bytes := adoqry.fieldByName(fld).AsBytes;
tmp := '';
for i := 0 to length(bytes) - 1 do
if bytes[i] < 32 then // strip any control characters (nulls, line feeds etc.) from the string
tmp := tmp + ' '
else
begin
case char(bytes[i]) of
'&': tmp := tmp + '&';
'''': tmp := tmp + ''';
'"': tmp := tmp + '"';
'>': tmp := tmp + '>';
'<': tmp := tmp + '<';
else
tmp := tmp + char(bytes[i]);
end;
end;
// when debugging, inc counter here to prove that the loop has been executed
writeln(f, UTF8String(tmp));
setLength(bytes, 0);
except on e: exception do
writeln(f, '');
end;
adoqry.next;
until adoqry.eof;
closefile(f);
问题
上面的代码会跳过一条记录(即只执行循环 n - 1 次,其中 n 是记录数)有什么原因吗?是否有什么会导致 "adoquery.next" 调用跳过记录?
编辑以澄清评论中提出的问题
报告中缺少数据。它始终是未处理的单个记录。我在报告中有超过 20,000 条记录,丢失的记录在中间的某个地方,但由于数据太多,很难缩小范围。当跳过一条记录时,该记录之后的所有内容都会向上移动一条记录(这意味着很多报告都是错误的),最后一条记录包含一个空白字段。
我似乎偶然发现了这个问题的解决方案。我仍在测试中,但目前似乎已经修复了问题。
在开始之前,我找到了被跳过的记录。有许多记录中的数据完全相同。我删除了被跳过的记录以查看会发生什么,并且处理过程跳过了不同的记录(包含相同的数据)。和以前一样,它只是间歇性地跳过它(每两个或三个查询一次 运行s)。
进入 "fix"...
我想我会尝试对 TADOQuery 的配置方式进行一些调整,看看是否有任何效果。多年来,配置以下选项后 运行 一直很好:
adoqry.executeOptions := [eoAsyncFetch];
我注释掉了这一行,突然处理工作正常了。我有 运行 几个查询,它们都返回所有行。什么都没有被跳过。我会继续测试,但这似乎(目前)已经解决了问题。
application/processing
的说明我正在 Delphi XE 中维护一些旧代码。该应用程序对远程服务器上的数据库运行查询,然后在 PC 上创建报告。我们有一个错误报告,其中一个字段中的某些数据丢失。有问题的字段包含从服务器收集的大量数据(几千个字符)。我无法控制该字段中收集和存储的数据。我发现该错误是由该数据中嵌入的空值和其他控制字符(换行符等)引起的。当调用 TADOQuery 的 SaveToFile 方法时,空值和其他控制字符导致字段中稍后的任何数据被忽略(SaveToFile 基本上到达控制字符并停止读取记录)。
该错误的解决方案是从结果集中提取有问题的字段,过滤掉所有控制字符并将其保存到临时文件(此时我无法将其放回结果集中,因为它处于只读状态)。数据保存为 XML 所以我还必须使一些字符 XML 友好(正如您将在代码片段中看到的那样)。调用 SaveToFile 方法后,我将从临时文件中读取更正后的数据并将其写回到已保存的报告中。它冗长但有效。
问题
我现在有一个新问题。我注意到在随机情况下,文件末尾会丢失一条记录(相关字段为空白)。我花了很长时间来研究这个问题,它归结为以下代码(用于在调用 SaveToFile 之前从字段中提取数据)。该代码正在跳过一行。不是每次——大约每两到三个查询运行中就有一个。我知道这是事实,因为我在调试时在下面的循环中添加了一个计数器,并将循环执行的次数与记录计数进行了比较,并且在发生错误时它返回的次数少了一个(导致空白字段)并且当所有数据都出现在报告中时相等。没有捕获到任何异常,因此它不会跌倒在某些东西上 - 它实际上是在跳过一条记录。
assignfile(f, tempFilename);
rewrite(f);
adoqry.first;
repeat
try
bytes := adoqry.fieldByName(fld).AsBytes;
tmp := '';
for i := 0 to length(bytes) - 1 do
if bytes[i] < 32 then // strip any control characters (nulls, line feeds etc.) from the string
tmp := tmp + ' '
else
begin
case char(bytes[i]) of
'&': tmp := tmp + '&';
'''': tmp := tmp + ''';
'"': tmp := tmp + '"';
'>': tmp := tmp + '>';
'<': tmp := tmp + '<';
else
tmp := tmp + char(bytes[i]);
end;
end;
// when debugging, inc counter here to prove that the loop has been executed
writeln(f, UTF8String(tmp));
setLength(bytes, 0);
except on e: exception do
writeln(f, '');
end;
adoqry.next;
until adoqry.eof;
closefile(f);
问题
上面的代码会跳过一条记录(即只执行循环 n - 1 次,其中 n 是记录数)有什么原因吗?是否有什么会导致 "adoquery.next" 调用跳过记录?
编辑以澄清评论中提出的问题
报告中缺少数据。它始终是未处理的单个记录。我在报告中有超过 20,000 条记录,丢失的记录在中间的某个地方,但由于数据太多,很难缩小范围。当跳过一条记录时,该记录之后的所有内容都会向上移动一条记录(这意味着很多报告都是错误的),最后一条记录包含一个空白字段。
我似乎偶然发现了这个问题的解决方案。我仍在测试中,但目前似乎已经修复了问题。
在开始之前,我找到了被跳过的记录。有许多记录中的数据完全相同。我删除了被跳过的记录以查看会发生什么,并且处理过程跳过了不同的记录(包含相同的数据)。和以前一样,它只是间歇性地跳过它(每两个或三个查询一次 运行s)。
进入 "fix"...
我想我会尝试对 TADOQuery 的配置方式进行一些调整,看看是否有任何效果。多年来,配置以下选项后 运行 一直很好:
adoqry.executeOptions := [eoAsyncFetch];
我注释掉了这一行,突然处理工作正常了。我有 运行 几个查询,它们都返回所有行。什么都没有被跳过。我会继续测试,但这似乎(目前)已经解决了问题。