В процессе эксплуатации информационных баз 1С, особенно после аварийных сбоев, прерывания транзакций или некорректных обновлений конфигурации, можно столкнуться с нарушением ссылочной целостности данных. Типичный пример такой проблемы — появление «осиротевших» строк в табличных частях: физически строки в таблице существуют, но родительский документ был удален или поврежден, из-за чего обращение к ссылке возвращает <Объект не найден> или NULL.
Проанализируем ситуацию на примере запроса к табличной части документа:
ВЫБРАТЬ
ЗаказКлиентаТовары.Ссылка КАК Ссылка,
ЗаказКлиентаТовары.НомерСтроки КАК НомерСтроки,
ЗаказКлиентаТовары.Номенклатура КАК Номенклатура
ИЗ
Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
ГДЕ
ЗаказКлиентаТовары.Ссылка.Номер ЕСТЬ NULL
В объектной модели «1С:Предприятие» табличные части не являются отдельными ссылочными объектами и не имеют собственных менеджеров для записи или удаления без родительского документа. Поэтому просто вызвать метод удаления строки нельзя. Разберем по шагам несколько эффективных способов решения этой проблемы.
Самый простой и стандартный способ очистки битых ссылок и осиротевших записей — использование встроенной утилиты администрирования в конфигураторе. По умолчанию параметры утилиты не удаляют поврежденные записи, поэтому важно задать правильные настройки.
Если требуется удалить конкретные осиротевшие строки без полного тестирования всей базы данных, можно восстановить родительский документ по его УникальныйИдентификатор, связать его с висящими строками и затем удалить стандартными методами платформы.
Разберем пример программного кода для восстановления и удаления потерянного документа:
// 1. Получаем список битых ссылок
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ЗаказКлиентаТовары.Ссылка КАК Ссылка
|ИЗ
| Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
|ГДЕ
| ЗаказКлиентаТовары.Ссылка.Номер ЕСТЬ NULL";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем GUID битой ссылки
СсылкаНаОбъект = Выборка.Ссылка;
// Создаем новый документ и явно назначаем ему сохраненную ссылку
НовыйДокумент = Документы.ЗаказКлиента.СоздатьДокумент();
НовыйДокумент.УстановитьСсылкуНового(СсылкаНаОбъект);
// Записываем документ, чтобы восстановить ссылочную целостность
НовыйДокумент.Записать();
// Теперь документ существует в базе вместе со своими строками ТЧ
// Удаляем его непосредственно или помечаем на удаление
НовыйДокумент.Удалить();
КонецЦикла;
Рассмотрим подробнее, как работает этот алгоритм: метод УстановитьСсылкуНового() связывает создаваемый объект с уже существующим идентификатором в табличной части. Последующий вызов метода Удалить() очищает как шапку документа, так и все связанные с ним подчиненные строки.
В случаях, когда повреждения базы слишком масштабны или тестирование средствами конфигуратора завершается аварийно, можно прибегнуть к очистке на уровне реляционной СУБД (Microsoft SQL Server, PostgreSQL и др.).
ПолучитьСтруктуруХраненияБазыДанных() определяем имя физической таблицы документа (шапки) и имя таблицы табличной части, а также имена полей ссылок.
DELETE FROM _Document123_VT456
WHERE _Document123_IDRRef NOT IN (
SELECT _IDRRef FROM _Document123
);
1С:Предприятие.Важно: прямое вмешательство в базу данных на уровне СУБД следует использовать с осторожностью и только при наличии свежего бэкапа, так как некорректные запросы могут нарушить целостность других связанных таблиц.