【问题标题】:Delphi TADOQuery.next skipping a recordDelphi TADOQuery.next 跳过一条记录
【发布时间】:2015-06-24 22:19:52
【问题描述】:

申请/处理的描述

我在 Delphi XE 中维护一些旧代码。该应用程序在远程服务器上的数据库上运行查询,然后在 PC 上创建报告。我们收到了一个错误报告,其中一个字段中的某些数据丢失。有问题的字段包含从服务器收集的大量数据(几千个字符)。我无法控制在该字段中收集和存储哪些数据。我发现错误是由嵌入在此数据中的空值和其他控制字符(换行符等)引起的。当调用 TADOQuery 的 SaveToFile 方法时,空值和其他控制字符导致字段中的任何数据被忽略(SaveToFile 基本上到达控制字符并停止读取记录)。

该错误的解决方案是从结果集中提取有问题的字段,过滤掉任何控制字符并将其保存到临时文件中(此时我无法将其放回结果集中,因为它在只读状态)。数据保存为 XML,因此我还必须使一些字符 XML 友好(正如您将在代码 sn-p 中看到的那样)。调用 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 + '&amp;';
                      '''': tmp := tmp + '&apos;';
                      '"': tmp := tmp + '&quot;';
                      '>': tmp := tmp + '&gt;';
                      '<': tmp := tmp + '&lt;';
                 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”调用跳过记录吗?

编辑以澄清 cmets 中提出的问题

报告中缺少数据。它始终是未处理的单个记录。我在报告中有超过 20,000 条记录,缺少的记录在中间的某个位置,但是由于数据量如此之大,很难缩小范围。由于正在跳过一条记录,该记录之后的所有内容都会上移一条记录(这意味着很多报告都是错误的),最终记录包含一个空白字段。

【问题讨论】:

  • 这不是你的问题的原因,但你不应该使用重复循环来迭代数据集。改用“while not DataSet.Eof do”。这样,如果数据集恰好为空,您的代码就不会出错。
  • 您是否尝试过简化您的代码?像qry.First; while not qry.Eof do begin Writeln(f, qry.Fields[0].AsString); qry.Next; end; 这样的东西?如果这个最简单的代码不能重现您的问题,那么问题出在其他地方。
  • 顺便说一句,当您调用 .SaveToFile 时,您是否使用传递 pfADTG 或 pfXML 作为 TPersistfile 参数?如果你使用另一个,你会遇到同样的问题吗?在我看来,像 SaveToFile 这样广泛使用的例程在写入文件时会错误地转义数据。
  • 您说“(相关字段将为空白)”。是空白还是缺失。如果异常,则写出一个空行,然后将计数器放在 try 块中。如果临时文件中的行数正确,但计数器错误,那么您一定遇到了异常。我遇到过由于我的选择而导致 IDE 没有中断的异常情况。我以为我没有真正击中 except 块。试着在 adoqry.net 之前移动计数器,看看你得到了什么数字。
  • 你在用线程吗?

标签: delphi tadoquery


【解决方案1】:

我似乎偶然发现了解决此问题的方法。我仍在测试,但目前似乎已经解决了问题。

在我开始之前,我追踪了被跳过的记录。有许多记录具有完全相同的数据。我删除了被跳过的记录以查看会发生什么,并且处理跳过了另一条记录(包含相同的数据)。和以前一样,它只是间歇性地跳过它(每两到三个查询运行一次)。

进入“修复”...

我想我会尝试对 TADOQuery 的配置方式进行一些调整,看看是否有任何效果。多年来,在配置了以下选项后,它一直运行良好:

adoqry.executeOptions := [eoAsyncFetch];

我注释掉了这条线,突然处理工作正常。我已经运行了几个查询,它们都返回了所有行。没有任何内容被跳过。我会继续测试,但这似乎(目前)有固定的东西。

【讨论】:

  • 嗯,是的,如果您使用线程,该选项绝对没有意义,如果该选项处于活动状态,您需要等待OnFetchComplete 事件,只有这样您才知道所有数据都已获取...
  • @whosrdaddy 是的,确实。在收到您的评论提示后,我在配置中进行了挖掘并发现了这一点。在我们将运行的查询移动到线程中并被忽略之前,一定已经在那里了。
猜你喜欢
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 2015-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多