2015-06-23 8 views
0

Описание приложения/обработкиDelphi TADOQuery.next пропуская рекордную

Я поддерживать некоторый старый код в Delphi XE. Приложение запускает запрос в базе данных на удаленном сервере, а затем создает отчет на ПК. У нас был отчет об ошибке, что некоторые данные в одном из полей отсутствуют. В рассматриваемом поле содержится огромное количество данных (несколько тысяч символов), собранных с сервера. Я не контролирую, какие данные собираются и хранятся в этом поле. Я обнаружил, что ошибка вызвана ошибками и другими управляющими символами (линейными каналами и т. Д.), Встроенными в эти данные. Когда был вызван метод SaveToFile TADOQuery, нули и другие управляющие символы приводили к игнорированию любых данных в поле в поле (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 + '&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 раз, где п является количество записей)? Есть ли что-то, что вызовет вызов adoquery.next для пропуска записи?

Редактировать для разъяснения вопросов, поднятых в комментариях

отсутствуют данные отчета. Это всегда одна запись, которая не обрабатывается. У меня более 20 000 записей в отчете, а отсутствующая запись находится где-то посередине, но ее трудно сузить, так как имеется так много данных. Поскольку одна запись пропускается, все после этой записи сдвигает запись (что означает, что большая часть отчета ошибочна), причем окончательная запись содержит пустое поле.

+4

Это не причина вашей проблемы, но вы никогда не должны использовать цикл повтора для итерации набора данных. Вместо этого используйте «while not DataSet.Eof do». Таким образом, ваш код не пойдет не так, если набор данных окажется пустым. – MartynA

+0

Вы попробовали упростить свой код? Что-то вроде 'qry.First; а не qry.Eof do begin Writeln (f, qry.Fields [0] .AsString); qry.Next; конец; '? Если этот простейший код не воспроизводит вашу проблему, проблема в другом месте. – Abelisto

+0

Btw, когда вы вызываете .SaveToFile, используете ли вы использование pfADTG или pfXML в качестве параметра TPersistfile? И возникает ли у вас такая же проблема, если вы используете другую? Мне кажется маловероятным, что, поскольку широко используется обычная программа, так как SaveToFile будет некорректно избегать данных, когда она записывает файл tp. – MartynA

ответ

0

Я, кажется, наткнулся на решение этой проблемы. Я все еще тестирую, но на данный момент, похоже, исправлены.

Прежде чем я получу в этом, я обнаружил пропущенную запись. Существует ряд записей с точно такими же данными в них. Я удалил пропущенную запись, чтобы увидеть, что произойдет, и обработка пропустила другую запись (содержащую те же данные).Как и раньше, он просто пропускал его с перерывами (один раз в каждые два или три запроса).

Onto в «исправить» ...

Я думал, что я пытаюсь сделать несколько настроек, чтобы как TADOQuery был настроен, чтобы увидеть, что если какое-либо воздействие. В течение многих лет, это было отлично работает со следующей опцией сконфигурированной:

adoqry.executeOptions := [eoAsyncFetch]; 

Я прокомментировал эту строку и вдруг обработка работает отлично. Я запустил несколько запросов, и все они возвращаются со всеми строками. Ничто не пропускается. Я продолжу тестировать, но это кажется (на данный момент) фиксированными вещами.

+0

Mmm yeah, Этот параметр абсолютно не имеет смысла, если вы используете потоки, если это активно, вам нужно дождаться события 'OnFetchComplete', только тогда вы знаете, что все данные были получены ... – whosrdaddy

+0

@whosrdaddy Да, действительно. Я выкопался в конфиге после запроса вашего комментария и наткнулся на это. Должно быть, он был там с тех пор, пока мы не переместили запрос в потоки и не просмотрели. – Jeedee