Класс TBtrFile (потомок TbFile) с поддержкой журнализации и фильтром записей
Скачать (zip-файл; Размер - 32751)Обсудить в форуме
Описание
Класс, являющийся наследником от TbFile, c расширенными возможностями. Возможность фильтрации записей, как просто путем задания условий на поля, так и возможность отобрать определенный диапазон записей, путем задания границ диапазона, то есть первой и последней записи при данном ключе. Возможна и комбинация этих двух способов фильтрации, то есть сначала задаем диапазон, а затем дополнительные условия фильтрования.
Класс поддерживает журнализацию всех изменений в БД с записью в operlog.dbt (для RS-Bank), при написании этого функционала был частично использован класс xOperLog из данной библиотеки (Хондожко И.В., ИС-Банк). Как и у первоисточника, контрольная сумма не заполняется (однако никаких проблем за время эксплуатации с 2009-го года это не вызвало).
В прилагаемом архиве находятся следующие файлы:
_tbtrfile.mac - класс TBtrFile
_common_const.mac, _kbdcodes.mac - всякие константы
_func_lib.mac - используемые функции и процедуры
_common_classes.mac - библиотека вспомогательных классов
_tfields.mac - классы для стандартных типов данных
_toperlog - класс, используемый для журнализации
Во вспомогательных файлах осталось много не относящегося к данному примеру, но вычищать все основательно просто нет времени. Впрочем, там много всякой нужной всячины, может кому что и пригодится.
В файле _tfiles.mac содержится ряд примеров использования класса, например, arhdoc за заданный диапазон дат, кассовые символы для документа, счета по маске и по балансовому счету, и.т.д.
Ниже подробно разбирается один из этих примеров - архивные документы.
Класс этот активно мной используется где-то с 2009-го или 2010-го года, если нужно открывать постоянную таблицу БД на запись - только его и использую, не приходится озабачиваться журнализацией. Но operlog приходится архивировать регулярно, растет в разы быстрее, чем на дистрибутиве. Из серьезных недостатков класса - сильно тормозит метод NRecords при большом числе записей, так как работает тупым перебором. В ряде случаев советую переопределить этот метод с использованием SQL, это гораздо быстрее, но, к сожалению, не универсально и требует писать запрос руками для каждого конкретного случая. Сгенерить запрос на автомате базируясь только на том, как задается фильтрация, у меня не получилось. Еще один тонкий момент - если задали границы диапазона по какому-то ключу, менять его уже нельзя, получится полная ерунда. Надеюсь, эта разработка кому-нибудь да пригодится.
Класс поддерживает журнализацию всех изменений в БД с записью в operlog.dbt (для RS-Bank), при написании этого функционала был частично использован класс xOperLog из данной библиотеки (Хондожко И.В., ИС-Банк). Как и у первоисточника, контрольная сумма не заполняется (однако никаких проблем за время эксплуатации с 2009-го года это не вызвало).
В прилагаемом архиве находятся следующие файлы:
_tbtrfile.mac - класс TBtrFile
_common_const.mac, _kbdcodes.mac - всякие константы
_func_lib.mac - используемые функции и процедуры
_common_classes.mac - библиотека вспомогательных классов
_tfields.mac - классы для стандартных типов данных
_toperlog - класс, используемый для журнализации
Во вспомогательных файлах осталось много не относящегося к данному примеру, но вычищать все основательно просто нет времени. Впрочем, там много всякой нужной всячины, может кому что и пригодится.
В файле _tfiles.mac содержится ряд примеров использования класса, например, arhdoc за заданный диапазон дат, кассовые символы для документа, счета по маске и по балансовому счету, и.т.д.
Ниже подробно разбирается один из этих примеров - архивные документы.
Класс этот активно мной используется где-то с 2009-го или 2010-го года, если нужно открывать постоянную таблицу БД на запись - только его и использую, не приходится озабачиваться журнализацией. Но operlog приходится архивировать регулярно, растет в разы быстрее, чем на дистрибутиве. Из серьезных недостатков класса - сильно тормозит метод NRecords при большом числе записей, так как работает тупым перебором. В ряде случаев советую переопределить этот метод с использованием SQL, это гораздо быстрее, но, к сожалению, не универсально и требует писать запрос руками для каждого конкретного случая. Сгенерить запрос на автомате базируясь только на том, как задается фильтрация, у меня не получилось. Еще один тонкий момент - если задали границы диапазона по какому-то ключу, менять его уже нельзя, получится полная ерунда. Надеюсь, эта разработка кому-нибудь да пригодится.
Текст примера
class (TBtrFile) TFArhDoc(_bdate:@date, _edate:@date, _chap:@integer, _code_curr:@integer, _mode:@string) var BegDate :date = NVL(_bdate, ZERO_DATE); // начальная дата var EndDate :date = NVL(_edate, {curdate} - 1); // конечная дата var Chapter :integer = NVL(_chap, CHAPTER_BALANCE); // глава (по умолчанию 1-я) var Code_Curr:integer = NVL(_code_curr, RUR); // код валюты (по умолчанию рубли) var Mode :string = NVL(_mode, "R"); // режим открытия файла /******************************************************/ macro Filter(rec) // отбрасываем записи с Result_Carry 23 if (rec.rec.Result_Carry == RES_CARRY_DELETED) return FALSE; end; // отбрасываем записи не подходящие по дате проводки if ((rec.rec.Date_Carry < BegDate) or (rec.rec.Date_Carry > EndDate)) return FALSE; end; // фильтруем по коду валюты if ((Code_Curr > 0) and (rec.rec.Code_Currency != Code_Curr)) return FALSE; end; // фильтруем по главе if (GetDocChapter(rec) != Chapter) return FALSE; end; return Filter(rec); end; /******************************************************/ // номер ключа зависит от таблицы с документами // временный объект, таблица будет выбрана по главе и валюте local var iKey :integer = BoolToInt(Chapter != CHAPTER_BALANCE); local var ffTmp:object = SelectDocFile(Code_Curr, Chapter, DOC_TYPE_ARH, "TBtrFile", Mode); // вызов конструктора базового класса initTBtrFile(ffTmp.tblName, Mode, iKey, ffTmp.FileName, ffTmp.dicName); // флаг пустой выборки bEmpty = TRUE; // ищем по ключу первую запись диапазона (и удовлетворяющую фильтр) _extObj.Clear(); if (Chapter != CHAPTER_BALANCE) _extObj.rec.Chapter = Chapter; end; _extObj.rec.Date_Carry = BegDate; if (not _extObj.GetLT()) _extObj.Rewind(); end; while(_extObj.Next() and (GetDocChapter(_extObj) == Chapter) and (_extObj.rec.Date_Carry <= EndDate)) if (Filter(_extObj)) // запись найдена, фиксируем ее как первую и одновременно как последнюю запись диапазона FirstRec = TCRecord(this.tblName, this.dicName, this.KeyNum); LastRec = TCRecord(this.tblName, this.dicName, this.KeyNum); copy (FirstRec, _extObj); copy (LastRec , _extObj); bEmpty = FALSE; break; end; end; if (bEmpty) return; end; // ищем с другой стороны последнюю запись, и если нашли и она не совпадает с первой - переопределяем //верхнюю границу диапазона _extObj.Clear(); if (Chapter != CHAPTER_BALANCE) _extObj.rec.Chapter = Chapter; end; _extObj.rec.Date_Carry = EndDate; if (not _extObj.GetGT()) _extObj.Rewind(); end; while(_extObj.Prev() and (GetDocChapter(_extObj) == Chapter) and (_extObj.rec.Date_Carry >= BegDate)) if (Filter(_extObj)) copy (LastRec , _extObj); break; end; end; end;