TpFIBDataSet.PSReset - ошибка?

V.Borzov
Дата: 04.09.2019 17:24:42
Здравствуйте,

Может, кто сталкивался с такой проблемой:

Для копирования в TClientDataset из любого датасета всегда использовал TDatasetProvider:

+
     
     dsp := TDatasetProvider.Create(nil);
     try
        try
          dsp.DataSet := sourcedataset;
          destinationcds.data := dsp.data;
     finally
        dsp.Free;
     end;


Однако при копировании из tpFibDataset обнаружил, что датасет закрывается и открывается снова. В результате получаем двойную работу, если мы до этого уже открыли датасет и отфетчили все записи. Происходит это из-за PSReset:

+
procedure TpFIBDataSet.PSReset;
begin
  inherited PSReset;
  if Active then
  begin
    CloseOpen(False)
  end;
end;


В IBX, гляжу, то же самое. Но правильное ли это поведение? В комментариях к функции PSReset пишут, что она всего-навсего:

"Сбрасывает набор данных так, чтобы он был позиционирован на первую запись. Провайдер вызывает PSReset, чтобы снова установить набор данных на первой записи перед выборкой записей"

Обошел проблему через использование функции TDatasetProvider.GetRecords (при условии, что встаем на первую позицию и отфетчили все записи), но есть неприятность: калькулируемые поля включаются в датасет, но не пересчитываются, их значения будут NULL, ибо пересчитываются они как раз в TDatasetProvider.Reset, который заодно и PSReset использует. Поэтому универсального решения для копирования из любых dataset на все случаи жизни уже не получается, приходится учитывать контекст... Но проблемы бы не было, если разобраться с PSReset.

TBDEDataset использует в этой функции процедуру DbiForceReread, которая не приводит к переоткрытию, что TTable, что TQuery, и даже к некоему "обновлению данных "иначе бы давно ошибки повылазили, ибо часто делается запрос в TQuery из временной таблицы, лежащей, допустим, в темпе, открывается запрос, и временная таблица сразу удаляется. Поэтому такое копирование в TClientDataset всегда работало без проблем, и можно было зацапать и калькулируемые поля, и не беспокоиться, что датасет переоткроется.

Есть мнения по поводу того, как должен бы выглядеть правильный PSReset для tpFibDataset?
Dimitry Sibiryakov
Дата: 04.09.2019 17:41:24

V.Borzov
как должен бы выглядеть правильный PSReset для tpFibDataset?

Как вызов First().

Posted via ActualForum NNTP Server 1.5

ёёёёё
Дата: 05.09.2019 12:36:54
V.Borzov
...В IBX, гляжу, то же самое. Но правильное ли это поведение?...

Вопрос имел бы смысл, если бы ты был разработчиком этих библиотек.
А так - утрись и используй то, что есть. Или не используй.
V.Borzov
Дата: 05.09.2019 12:50:10
ёёёёё,
Я не предлагаю пользоваться моими корректировками. Но для себя я их делаю. В чем проблема-то? Зачем мне утираться ошибкой, если я могу её сам исправить, а не делать затыки в зависящих от неё функциях?
ёёёёё
Дата: 05.09.2019 13:19:21
V.Borzov
ёёёёё,
Я не предлагаю пользоваться моими корректировками. Но для себя я их делаю. В чем проблема-то? Зачем мне утираться ошибкой, если я могу её сам исправить, а не делать затыки в зависящих от неё функциях?

Не сердись. Откуда мне знать, для чего ты спросил. Может, ты собираешь статистику "правильный/неправильный датасет с т.зр. оптимальнсти процедуры копирования данных в TClientDataset". Интересно же.
автор
Однако при копировании из tpFibDataset обнаружил, что датасет закрывается и открывается снова. В результате получаем двойную работу, если мы до этого уже открыли датасет и отфетчили все записи.

В результате время работы увеличивается на 18 миллисекунд, каждые сутки?
...
Вообще, тема чрезвычайно интересная - тут тебе и вопросы оптимизации, и целесообразности применения костыля типа TClientDataset, и методика заточки сторонних библиотек под свои нужды.
Квейд
Дата: 05.09.2019 13:31:19
Мне в ODAC тоже пришлось это фиксить

procedure TCustomDADataSet.PSReset;
begin
  inherited PSReset;

  // <fix>
  if Active then
    First;
  Exit;
  // <fix>
  
  if Active then begin
    Close;
    Open;
  end;
end;
vavan
Дата: 05.09.2019 13:38:37
Квейд
Мне в ODAC тоже пришлось это фиксить
Картинка с другого сайта.
procedure TVADQuery.PSReset;
begin
  if Active then
    if FetchOptions.AutoClose then begin
      Close;
      { DONE -ovavan -cbug : no need to open it again }
      //Open;
    end
    else
    if not Bof then
      First;
end;
V.Borzov
Дата: 05.09.2019 13:49:51
ёёёёё
В результате время работы увеличивается на 18 миллисекунд, каждые сутки?

запрос выводит 1000-2000 строк с итоговыми суммами, после нескольких select from select всё выплевывается одним махом, на запрос уходит до 2 минут. В данном случае это критично.
V.Borzov
Дата: 05.09.2019 15:11:57
Во как! Я тут далеко не первый с этой функций. Что и требовалось выяснить :)
Всем спасибо.
V.Borzov
Дата: 05.09.2019 15:51:17
ёёёёё
Вообще, тема чрезвычайно интересная - тут тебе и вопросы оптимизации, и целесообразности применения костыля типа TClientDataset, и методика заточки сторонних библиотек под свои нужды.

TClientDataset вполне устраивает как таблица в памяти, не такой уж и костыль. И копирование данных указанным способом, вроде, очень быстрое и достаточно удобное, по крайней мере сравнивал как-то с известными бесплатными MemDataset, пришел к такому выводу. И всякие там легкие сортировки по набору полей и агрегатные функции, тоже неплохо. Одно печалит: ограничение на принятый размер данных <=500мегабайт примерно, по крайней мере в 32 разрядном Delphi XE. Буквально вчера обратился клиент, захотелось отчет ему большой, результат которого собирается в CDS и выводится в грид на экран, а отчет выдает ошибку. Объясняю, что в его случае надо либо уменьшать уровень детализации отчета, что дает 12 тыс строк хотя бы, вместо 600 тыс, либо вообще другие отчеты смотреть (а ей всего-то надо было ведомость реализации товаров за месяц со всех складов сразу с полной детализацией...). Но все-таки, ограничение неприятное, учитывая, что программа может под себя выделить до 2 гиг памяти, а в компе ихнем её очень много.