Распространённая ситуация: надо очистить справочник от лишних записей. Когда это записи вроде «test», никаких проблем возникнуть не должно. Но если название не такое «кричащее», появляются сомнения: а нет ли привязки к ID этой записи где-то в скрипте? Добро, если все ID аккуратно сложены в scr_Consts (где им и полагается быть), можно посмотреть туда и выяснить. Но бывает, что они валяются где попало. Даже заглянуть в scr_Consts – дело не быстрое, особенно, когда записей много. А уж искать по всем скриптам – огромная трата времени. К тому же, записи из справочников может удалить и пользователь, а он, порой, и не догадывается, что к ID удаляемой записи привязана какая-то логика. Как же быть? Была мысль сделать служебное поле «запрет удаления записи», но это только оттянет решение проблемы: рано или поздно встанет вопрос, ставить туда галочку, или нет. Да и добавлять такое поле в каждую таблицу каждого справочника, да логику обработки запретов, да приучиться пользоваться новым полем – всё это сложно и громоздко.
Предлагаю другой путь: при удалении записи из таблицы справочника действительно автоматически проверять, не указан ли её ID где-то в скриптах. И если указан – сообщать об этом, запрещая удаление. Положительные стороны такого подхода: быстрая реализация и надёжность. Отрицательная сторона – медленное удаление из справочника. Всё-таки, проверить ВСЕ скрипты на вхождение строки ID не быстро. В среднем выходит около трёх секунд. Однако, практика показала, что это не слишком высокая высокая плата за надёжность.
Вот, что следует сделать:
1. Эту функцию вставить в scr_Utils:
function FindTextInService(FindText){
//@АБ(all)
/*
Функция для поиска вхождения строки аргумента в тексте всех скриптов
Возвращает название скрипта, если строка найдена, и '', если такой строки нет
*/
var ServiceCount = Services.InformationsCount;
for (var i = 0; i ServiceCount; i++) {
var Info = Services.Informations(i);
var ServiceTypeCode = Info.ServiceTypeCode;
var USI = new String(Info.USI);
var CaptionUSI = ExtractUSICodeEx(Info.USI);
if (ServiceTypeCode == 'Script'){
try {
if (USI.indexOf('Call Centre') >= 0){
//для call-центра нет лицензии
continue;
}
var Service = Services.GetSingleItemByUSI(CaptionUSI);
var ServiceText = new String(Service.Text);
if (ServiceText.indexOf(FindText) >= 0){
//Если в тексте скрипта найдена строка поиска
//Log.Write(1, 'Строка '+FindText+' найдена в скрипте '+CaptionUSI);
return CaptionUSI;
}
}
catch (e){
//Вдруг ошибки лицензий
}
}
}
return '';
}
2. В scr_WindowUtils вставить в функцию DeleteDataGridRecords(DataGrid)
после строк:
if (KeyDataFieldNotExist) {
var Message = FormatStr(KeyDataFieldNotAssignedInDataset, Dataset.USI);
throw (Message);
}
вставить:
//@АБ Вставка проверки на возможность удаления из справочников часть 1
//(здесь определяется, что это - справочник.
//Критерии: либо сервис в папке 'Dictionaries',
//либо относится к группе таблиц 'TG_DICTIONARY')
var DatasetUSI = new String(Dataset.USI);
var IsDictionaryDataset = ((GetParentTableGroup(Dataset) == 'TG_DICTIONARY')||
(DatasetUSI.indexOf('Dictionaries') > 0));
//
и перед
вместо
вставить:
//@АБ Вставка проверки на возможность удаления из справочников
if (IsDictionaryDataset){
//Если удаляем из справочника
System.BeginProcessing(); //Начало показа
var FindScript = FindTextInService(ID);
System.EndProcessing(); //Конец показа
if (FindScript != ''){
//Если в скриптах используется такой ID, запрещаем удаление
ShowWarningDialog('Удаление невозможно:\nЗапись c ID = \''+
ID+'\'\n используется в скрипте '+FindScript);
DeleteNoPossibility = DeleteNoPossibility + 1;
continue;
} else {
//Запись не найдена - удаляем
Dataset.Delete();
}
} else {
Dataset.Delete();
}
Предложенная проверка не работает для идентификаторов, "зашитых" в параметры SelectQuery. Если есть опасность удалить такую запись, то стоит написать функцию, аналогичную описанной выше FindTextInService(FindText), но для поиска в параметрах всех запросов. Принцип тот же.