Каждый специалист, работающий с платформой «1С:Предприятие», рано или поздно сталкивается с загадочным поведением системы: элементы справочника (например, номенклатура) физически удалены из базы данных, но продолжают «всплывать» в отчетах, отображаться в реквизитах ранее созданных документов или предлагаться в истории быстрого выбора. При попытке выбрать такой элемент система выдает предупреждение: «эти данные невозможно выбрать, так как они были ранее удалены». В этой статье мы подробно разберем, почему возникает этот сбой, как устроена ссылочная целостность в 1С и какими способами можно полностью очистить базу от «призраков» удаленных объектов.
Давайте проанализируем, как платформа 1С хранит данные в СУБД. Каждый элемент справочника, документ или другой объект метаданных при создании получает уникальный 128-битный идентификатор — GUID (UUID). Когда вы выбираете номенклатуру в табличной части документа, в базу данных записывается не текстовое название товара, а именно этот GUID.
Если объект удаляется «непосредственно» (в обход стандартного механизма контроля ссылок), его запись полностью стирается из таблицы этого справочника. При этом в табличной части документа GUID удаленного объекта никуда не исчезает. Когда платформа пытается прочитать этот GUID, чтобы вывести представление пользователю, она делает запрос к таблице справочника, не находит там записи и отображает системную строку вида <Объект не найден> (уникальный идентификатор).
Выясним причины, по которым это происходит, ведь пользователь может быть уверен, что удалял элементы через стандартную «Пометку на удаление» и «Удаление помеченных объектов»:
Удалить() вместо штатной пометки на удаление. При программном удалении контроль ссылочной целостности по умолчанию отключен, если разработчик не реализовал его вручную.<Объект не найден>, защищая конфиденциальность данных.Довольно часто возникает ситуация: бухгалтер заходит в регистр накопления, видит, что он пуст (или документы, делавшие движения, отменены и удалены), но в отчете по остаткам все равно отображаются удаленные элементы. Проанализируем, почему это происходит.
Большинство отчетов в 1С строятся не на реальных таблицах движений регистров, а на базе виртуальных таблиц (например, РегистрНакопления.Продажи.Обороты или РегистрНакопления.ТоварыНаСкладах.Остатки). Для повышения быстродействия СУБД хранит уже рассчитанные итоги на начало каждого месяца в специальных таблицах итогов.
Если транзакция удаления документов или записей регистра прервалась аварийно, либо объект был удален некорректно программным путем, таблицы реальных движений очищаются, а вспомогательные таблицы итогов остаются заполненными. Из-за этого расхождения отчет продолжает «видеть» несуществующие остатки по удаленным элементам номенклатуры.
Даже после полного удаления объекта он может продолжать отображаться в выпадающем списке при вводе первых букв в поле реквизита. Это не баг, а штатное поведение платформы, выполняющее роль кэширования для удобства пользователя.
История выбора сохраняется индивидуально для каждого пользователя в специальной системной таблице базы данных (ХранилищеСистемныхНастроек). При открытии формы или начале ввода платформа не делает тяжелых запросов к базе данных для проверки существования элементов в истории — она просто выводит закэшированные строки. Проверка актуальности ссылки происходит только в момент непосредственного клика по строке, из-за чего и возникает ошибка выбора.
Это самый надежный и стандартный способ исправить нарушение ссылочной целостности («занулить» или восстановить битые ссылки) и пересчитать итоги регистров. Для его выполнения нам потребуется монопольный доступ к базе данных (все пользователи должны выйти из программы).
Рассмотрим по шагам процесс запуска этой процедуры:
Если элементы были удалены корректно, но продолжают мозолить глаза пользователям в подсказках при вводе, необходимо очистить историю выбора. Сделать это можно несколькими способами.
Способ А. Интерактивная очистка через интерфейс (для конфигураций на БСП):
Способ Б. Программная очистка для администратора:
Если вам необходимо быстро очистить историю выбора по определенному пользователю или по всем пользователям сразу без монопольного режима, вы можете запустить внешнюю обработку со следующим кодом:
// Очистка истории выбора для конкретного пользователя
ИмяПользователя = "ИвановИИ";
ХранилищеСистемныхНастроек.Удалить("ИсторияВыбора", , ИмяПользователя);
// Способ полной очистки истории выбора для текущего пользователя
ХранилищеСистемныхНастроек.Удалить("ИсторияВыбора", , ИмяПользователяИнформационнойБазы());
Также разработчик может превентивно отключить сохранение истории выбора для конкретного реквизита на форме. Для этого в свойствах поля ввода (в конфигураторе) нужно установить свойство ИсторияВыбораПриВводе в значение Не использовать.
На крупных предприятиях остановить работу базы данных для проведения «Тестирования и исправления» в Конфигураторе бывает крайне проблематично. Выясним, как найти и устранить битые ссылки в режиме «1С:Предприятие» («на лету»):
<Объект не найден>) во всех таблицах документов и регистров базы данных и заменяет его на существующий элемент номенклатуры (например, на специально созданную позицию «Товар удален»). После этого битые ссылки исчезнут.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТовары.Ссылка КАК ДокументСсылка,
| РеализацияТовары.Номенклатура КАК БитыйТовар
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Номенклатура.Представление ЕСТЬ NULL
| И НЕ РеализацияТовары.Номенклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Найден битый элемент в документе: " + Выборка.ДокументСсылка);
КонецЦикла;
КонецЕсли;
Этот метод основан на том, что у удаленного элемента отсутствует представление в базе данных (оно возвращает значение NULL), в то время как сама ссылка заполнена и не равна ПустаяСсылка.
Если элемент справочника был удален случайно, но у вас сохранилась копия базы данных (даже старая), где этот элемент еще существовал, вы можете восстановить его с сохранением оригинального идентификатора (GUID). Для этого:
<Объект не найден> исчезнет.Проанализировав все возможные варианты, мы видим, что наиболее быстрым и комплексным решением для файловых и небольших клиент-серверных баз является штатное Тестирование и исправление, дополненное периодической очисткой кэша истории выбора пользователей.