В процессе работы с платформой «1С:Предприятие» пользователи и начинающие разработчики часто сталкиваются с неочевидным поведением системы при удалении данных. Один из классических вопросов: что происходит со ссылками на элемент справочника, если мы помечаем его на удаление? Должна ли ссылка в других (зависимых) объектах очиститься автоматически, или она останется? А если она всё-таки пропала, то почему это произошло?
В этой статье мы подробно разберем внутренние механизмы работы платформы 1С на уровне базы данных, выясним все возможные причины «исчезновения» ссылок и составим пошаговую инструкцию по диагностике подобных ситуаций.
Для начала давайте разберем главное различие между понятиями «Пометить на удаление» и «Непосредственно удалить». Платформа 1С использует двухэтапную систему удаления объектов, что гарантирует целостность базы данных.
Когда мы устанавливаем элементу справочника пометку на удаление, на уровне СУБД (будь то Microsoft SQL Server, PostgreSQL или файловая база данных) происходят следующие процессы:
ПометкаУдаления (тип Булево) принимает значение Истина.Таким образом, стандартное поведение платформы однозначно: при пометке на удаление ссылка в зависимых объектах физически остается на месте. В интерфейсе программы рядом с представлением элемента просто появляется характерный значок с красным крестиком.
Если в вашей конфигурации после пометки элемента на удаление ссылка в другом справочнике всё же очистилась (стала пустой), это не стандартное поведение платформы, а результат работы сопутствующих механизмов. Проанализируем самые распространенные сценарии.
В конфигурациях 1С (особенно в типовых решениях, построенных на базе БСП — Библиотеки стандартных подсистем) часто закладывается бизнес-логика контроля ссылочной целостности. Разработчики могут программно очищать ссылки при записи помеченного объекта.
Очистка может выполняться несколькими способами:
ПередЗаписью или ПриЗаписи.ПередЗаписью с источником СправочникОбъект) может перехватывать запись элемента, определять, что у него изменился флаг пометки удаления, находить все связанные объекты через запрос и программно очищать в них этот реквизит.Очень часто ссылка никуда не исчезает из базы данных, но визуально на форме она кажется пустой. Это происходит из-за настроек отборов в конфигураторе.
Если для реквизита зависимого справочника на форме или в свойствах самого реквизита установлена связь параметров выбора или жесткий отбор, например, Отбор.ПометкаУдаления(Ложь), то платформа ведет себя следующим образом: как только элемент помечается на удаление, он перестает соответствовать условиям отбора. Поле ввода на форме не может отобразить элемент, не подходящий под фильтр, и визуально кажется пустым, хотя в самой базе данных значение реквизита по-прежнему заполнено.
Выясним еще одну важную деталь: не перепутана ли связь «Реквизит» со связью «Владелец-Подчиненный». Если один справочник подчинен другому, то в форме родительского справочника подчиненные элементы обычно выводятся в виде списка с динамическим отбором по владельцу. При этом в самом подчиненном справочнике ссылка на владельца хранится в системном поле Владелец. Если мы помечаем владельца на удаление, подчиненные элементы могут скрываться из видимости на форме из-за наложенных фильтров отображения, хотя физически связь не нарушена.
Иногда разработчики настраивают условное оформление для динамических списков или элементов формы. Например, если у связанного реквизита установлена пометка удаления, шрифт поля может окрашиваться в белый цвет (сливаясь с фоном) или поле может становиться недоступным/невидимым. Физически данные на месте, но пользователь их не видит.
Нельзя исключать человеческий фактор или запуск процессов непосредственного удаления. Если вместо установки пометки удаления была вызвана функция непосредственного удаления (например, метод Удалить() в коде или групповая обработка без контроля ссылок), объект стирается из базы физически. В этом случае в зависимых объектах ссылка превращается в так называемую «битую ссылку» — визуально она отображается как строка вида <Объект не найден> (84:b700...). При определенных настройках интерфейса такое поле также может выглядеть пустым.
Чтобы не гадать на ромашке, выполним несколько последовательных шагов для точного определения того, что произошло с данными в вашей системе.
Самый надежный способ узнать, очистился ли реквизит физически — написать прямой запрос к базе данных. Для этого нам понадобится внешняя обработка «Консоль запросов».
Допустим, у нас есть справочник Договоры, в котором есть реквизит Организация. Мы пометили на удаление одну из организаций. Проверим, осталась ли ссылка в договоре. Напишем следующий запрос:
ВЫБРАТЬ
Договоры.Ссылка КАК Договор,
Договоры.Организация КАК Организация,
Договоры.Организация.ПометкаУдаления КАК ОрганизацияПомеченаНаУдаление
ИЗ
Справочник.Договоры КАК Договоры
ГДЕ
Договоры.Ссылка = &СсылкаНаДоговор
Проанализируем результат выполнения запроса:
Организация содержит название нашей организации (даже со значком пометки удаления), а поле ОрганизацияПомеченаНаУдаление возвращает значение Истина — значит, физически ссылка в базе данных сохранена. Проблема исключительно в логике отображения на форме (проверяйте отборы и условное оформление).Организация вернуло значение Неопределено или пустую ссылку — значит, ссылка действительно была физически очищена сторонним алгоритмом.Если ссылка действительно очистилась физически, нам нужно выяснить, кто и в какой момент это сделал. Откроем Журнал регистрации (разделы «Администрирование» — «Обслуживание» — «Журнал регистрации») и настроим отбор:
Договоры).Проанализировав записи журнала, мы сможем увидеть, происходила ли запись связанного договора в ту же секунду, когда мы помечали на удаление организацию. Если запись была, обратите внимание на колонку «Сеанс» и «Пользователь» — часто там фигурирует либо имя текущего пользователя (что указывает на работу кода в вашей транзакции), либо «Фоновое задание» (автоматическая фоновая очистка).
Если журнал регистрации подтвердил автоматическое изменение зависимого объекта, займемся поиском виновного программного кода. Откроем конфигуратор и выполним глобальный поиск:
Ctrl + Shift + F для вызова диалога глобального поиска..Организация = Справочники.Организации.ПустаяСсылка() или просто имя реквизита в контексте записи.Общие -> Подписки на события и поищите подписки, у которых источником (поле Источник) выступает ваш первый справочник, а событием выбрано ПередЗаписью или ПриЗаписи. Проверьте обработчики этих подписок в общих модулях.Для наглядности рассмотрим пример кода, который разработчики часто помещают в подписки на события для автоматического зануления неактуальных связей:
Процедура ОчиститьСсылкиПриПометкеУдаления(Источник, Отказ) Экспорт
// Если объект пометили на удаление
Если Источник.ПометкаУдаления И Источник.Ссылка.ПометкаУдаления = Ложь Тогда
// Находим все зависимые договоры
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Договоры.Ссылка КАК Ссылка
|ИЗ
| Справочник.Договоры КАК Договоры
|ГДЕ
| Договоры.Организация = &Организация";
Запрос.УстановитьПараметр("Организация", Источник.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Блокируем и перезаписываем объект, очищая ссылку
ДоговорОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДоговорОбъект.Организация = Справочники.Организации.ПустаяСсылка();
Попытка
ДоговорОбъект.Записать();
Исключение
ЗаписьЖурналаРегистрации("ОчисткаСсылок", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось очистить ссылку в договоре: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Мы подробно разобрали, как пометка на удаление отражается в программе 1С. В штатной ситуации платформа бережно относится к данным и никогда самостоятельно не затирает заполненные реквизиты. Если ссылка визуально или физически пропала, всегда последовательно проверяйте базу данных прямым запросом, анализируйте журнал регистрации и исследуйте конфигурацию на наличие программных обработчиков в подписках на события или модулях объектов.