Призрачные напоминания

Бывает, что встречается ошибка: при запуске программы возникает окно напоминаний, не содержащее записей. Причина в том, что для проверки, есть ли напоминания, в scr_Main используется функция GetAreRemindingsExist(), в которой опрашивается датасет ds_RemindingsCount. Он возвращает значения из таблицы tbl_Reminding. Там и вправду может быть напоминание. Но объекта, на которое ссылается это напоминание, может по каким-то причнам не быть. А в гриде окошка напоминаний используется другой датасет, ds_Remindings. В нём данные получаются из сложного запроса со множеством UNION ALL, но важно то, что выбирает он из таблиц, на которые в принципе может ссылаться поле "SubjectID" таблицы tbl_Reminding.

Так может возникнуть ситуация: напоминание есть, а объекта, к которому создано напоминание - уже нет. Поэтому окно показывается (существуют напоминания), но грид выводится пустым (объектов, о которых напоминание, нет).

Лечить это можно так:
в скрипте scr_Main, в функции GetAreRemindingsExist() в самом конце, перед return (Count > 0); поставить такую конструкцию:

if (Count > 0){
//Если найдены напоминания - проверяем, существуют ли связанные объекты
var RemindingsDataset = GetSingleItemByCode('ds_Remindings', 'CheckExistingRecords');
        ApplyDatasetFilter(RemindingsDataset, 'ContactID', ContactParameter.ValAsGUID, true);
        ApplyDatasetFilter(RemindingsDataset, 'RemindTime', today.getVarDate(), true);
        RemindingsDataset.Open();
        Count = (RemindingsDataset.IsEmptyPage ? 0 : Count); // или поменять на
        //Count = RemindingsDataset.RecordsCount; // альтернативный, более медленный способ, возвращающий точное количество напоминаний с действительно существующими объектами
        RemindingsDataset.Close();
}

Это избавит от "призрачных" напоминаний, но не ликвидирует, конечно, причину их появления.

Нравится

Поделиться

4 комментария

Может быть оптимальнее использовать след. строки вместо var RemindingsDataset = Services.GetNewItemByUSI('ds_Remindings');

var RemindingsDataset = GetSingleItemByCode('ds_Remindings', 'CheckExistingRecords');
RemindingsDataset.Close();

С GetSingleItemByCode быстрее, конечно. Тем более, что проверка напоминаний происходит регулярно. Подправил, но решил строку с RemindingsDataset.Close() повторно не вставлять, рассуждая так: в первый раз датасет будет закрыт, а в последующие - зарыт при выходе из функции (там закрытие есть). Главное, твёрдо помнить, что с таким кодом датасет используется только здесь.

Более того, датасет (если он DBDataset) автоматически закрывается в теле приведенной функции GetSingleItemByCode(...). Кроме того, вместо

Count = RemindingsDataset.RecordsCount; 

, который выполняет дополнительный запрос типа SELECT COUNT(*) FROM ...

советовал бы написать код вроде:

Count = (RemindingsDataset.IsEmptyPage ? 0 : Count);

Будет работать немного быстрее.

Спасибо, Артём!

А и вправду (сейчас посмотрел и убедился), GetSingleItemByCode всегда закрывает сервис, если он DBDataset. По крайней мере, так в 3.2.1.

Что же касается .RecordsCount, то, конечно, это свойство не стоит использовать для проверки, существует ли хоть одна запись, ведь оно генерирует дополнительный запрос с count(*). Лучшие, согласен, использовать .IsEmptyPage. Но дело в том, что в функции (GetAreRemindingsExist(), в базовой её части) используется именно количество: переменная Count получается, как раз, запросом по count(*), хотя и в неявной форме: var Count = Main.RemindingsDataset.Values('Count');
(указанный датасет содержит запрос с count(*)). Моя вставка подменяет значение этой переменной count (содержащий количество напоминаний) на количество напоминаний, имеющих связанные объекты.

Если взять Count = (RemindingsDataset.IsEmptyPage ? 0 : Count); мы получим в результате Count с количеством напоминаний, а не с количеством напоминаний с существующими объектами, когда RemindingsDataset.IsEmptyPage не будет true; то есть записей меньше, но они всё-таки есть.

Однако, поскольку функция всё равно возвращает return (Count > 0); то, получается, безразлично, "правильно" мы вычислили Count, или нет. Так что я согласен: Count = (RemindingsDataset.IsEmptyPage ? 0 : Count); даст выигрыш на один запрос. Сейчас исправлю. Хотя, наверное, стоило бы и саму функцию с датасетом перекроить: помещать в базовую перменную count сразу проверку на существование связанных с напоминанием объектов. Изменить её Select Query, к примеру.

Показать все комментарии