В практике разработки на платформе 1С:Предприятие 8 часто возникает задача: пользователь помечает на удаление элемент непосредственно из формы списка (не открывая форму элемента), а система должна предупредить его о том, где данный элемент уже задействован, или вовсе заблокировать операцию. Разберем ограничения платформы, особенности работы клиент-серверной архитектуры и надежные способы решения этой задачи.
Прежде чем приступать к реализации, проанализируем поведение управляемых форм и модуля объекта:
ПередУстановкойПометкиУдаления. В управляемом интерфейсе у таблицы формы с источником «Динамический список» такого события нет. Стандартное событие таблицы ПередУдалением вызывается исключительно при физической попытке удаления записи (комбинация Shift + Del), но не реагирует на обычное нажатие клавиши Del или команду контекстного меню «Пометить на удаление / Снять пометку».ПередЗаписью, ПриЗаписи) и подписки на события выполняются строго на стороне сервера внутри транзакции записи. В этом контексте запрещены любые интерактивные вызовы: ОткрытьФорму, ПоказатьВопрос или Предупреждение. Сервер не может приостановить выполнение кода и ожидать ответа пользователя на клиенте.Если бизнес-логика требует запретить пометку на удаление при наличии связей либо проинформировать пользователя кликабельным списком документов, рассмотрим реализацию проверки в процедуре ПередЗаписью модуля объекта или в подписке на событие.
Для корректной работы алгоритма необходимо соблюдать важные условия:
ОбменДанными.Загрузка, чтобы проверка не блокировала синхронизацию данных и пакетные обмены.ЭтотОбъект.ПометкаУдаления должно быть истинным, а исходное состояние в базе ЭтотОбъект.Ссылка.ПометкаУдаления — ложным.СообщениеПользователю или функцию ОбщегоНазначения.СообщитьПользователю из Библиотеки стандартных подсистем (БСП). Установка свойства КлючДанных превращает сообщение на клиенте в гиперссылку, по клику на которую открывается использующий документ.Посмотрим на пример реализации в модуле объекта:
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Проверяем, что пометка именно устанавливается, а не снимается
Если ЭтотОбъект.ПометкаУдаления И НЕ ЭтотОбъект.Ссылка.ПометкаУдаления Тогда
// Получаем ссылки, где используется текущий объект
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(Ссылка);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТаблицаСсылок.Количество() > 0 Тогда
// Ограничиваем вывод первыми несколькими записями, чтобы не перегружать интерфейс
МаксКоличество = Мин(ТаблицаСсылок.Количество(), 5);
Для Индекс = 0 По МаксКоличество - 1 Цикл
СтрокаДанных = ТаблицаСсылок[Индекс];
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Объект используется в: " + Строка(СтрокаДанных.Данные);
Сообщение.КлючДанных = СтрокаДанных.Данные;
Сообщение.Сообщить();
КонецЦикла;
Если ТаблицаСсылок.Количество() > МаксКоличество Тогда
ОбщегоНазначения.СообщитьПользователю(
СтрШаблон("И еще в %1 местах...", ТаблицаСсылок.Количество() - МаксКоличество)
);
КонецЕсли;
// Если требуется полностью запретить установку пометки:
// Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При таком подходе платформа передает стек сообщений на клиент. Пользователь увидит список зависимых документов в панели сообщений и сможет сразу перейти в любой из них двойным щелчком.
Разберем важный нюанс: вызов глобального метода НайтиПоСсылкам осуществляет полнотекстовый поиск по всем таблицам конфигурации, где теоретически может содержаться ссылка на данный объект. Если выполнять эту процедуру в высоконагруженной базе (например, 1С:ERP или Комплексная автоматизация), транзакция записи может заблокировать таблицы на длительное время. При попытке групповой пометки элементов система рискует столкнуться с взаимоблокировками или критическим падением скорости.
Чтобы избежать проблем с производительностью, заменим универсальный поиск ссылок прямым точечным запросом к ключевым регистрам или документам, где появление объекта критично:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 5
| Таблица.Ссылка КАК Ссылка
|ИЗ
| Документ.ЗаказКлиента.Товары КАК Таблица
|ГДЕ
| Таблица.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбщегоНазначения.СообщитьПользователю(
"Товар найден в заказе!",
Выборка.Ссылка
);
КонецЦикла;
Если бизнес-требования диктуют интерактивный сценарий: открыть диалоговое окно со списком ссылок и спросить пользователя «Объект используется в 10 документах. Вы уверены, что хотите пометить его на удаление?», перехватывать событие в модуле объекта нельзя. Всю цепочку потребуется перенести на клиентский уровень формы списка.
Разберем пошаговый алгоритм настройки формы списка:
ПометитьНаУдаление (или убираем автозаполнение командной панели).УстановитьПометкуУдаленияПользовательская, выносим её на командную панель и назначаем ей сочетание клавиш Del.ПоказатьВопрос.Объект.УстановитьПометкуУдаления(Истина).Посмотрим на пример клиентского кода в форме списка:
&НаКлиенте
Процедура КомандаПометитьНаУдаление(Команда)
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
ВыбраннаяСсылка = ТекущиеДанные.Ссылка;
// Проверяем наличие связей на сервере
КоличествоСсылок = ПроверитьИспользованиеНаСервере(ВыбраннаяСсылка);
Если КоличествоСсылок > 0 Тогда
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопросОПометке", ЭтотОбъект, ВыбраннаяСсылка);
ТекстВопроса = СтрШаблон("Объект используется в других данных (%1 мест). Все равно пометить на удаление?", КоличествоСсылок);
ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
Иначе
УстановитьПометкуНаСервере(ВыбраннаяСсылка, Истина);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопросОПометке(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
УстановитьПометкуНаСервере(ДополнительныеПараметры, Истина);
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
Таким образом, для простых сценариев и жестких запретов оптимально использовать серверный метод СообщениеПользователю в процедуре ПередЗаписью. Для сценариев с интерактивным выбором и подтверждением пользователя следует переопределять стандартную команду удаления в форме списка.