При работе с базами данных 1С, особенно после переноса данных или некорректных операций, мы можем столкнуться с ситуацией, когда в регистрах сведений, документах или других объектах появляются ссылки на объекты, которые фактически были удалены из базы. Такие ссылки отображаются в интерфейсе как "Объект не найден", и напрямую удалить их бывает непросто, поскольку они не равны NULL или Неопределено в привычном понимании. В этой статье мы подробно разберем, как эффективно найти и удалить такие записи из регистра сведений, используя различные методы.
Наш конкретный случай касается регистра сведений "Штрихкоды" в базе 1С:Розница, где поле "Владелец" (которое может быть составного типа и ссылаться, например, на Справочник.Номенклатура) содержит битые ссылки.
.Ссылка ЕСТЬ NULLПрежде чем перейти к методам удаления, давайте выясним, почему прямые проверки на NULL или Неопределено не работают для битых ссылок.
Когда мы видим в поле ссылочного типа значение "Объект не найден", это означает, что объект, на который указывала эта ссылка, был удален из информационной базы. Сама ссылка при этом не обнуляется и не становится Неопределено. Она остается как "фантомная" ссылка, ведущая в никуда, сохраняя при этом свою внутреннюю структуру, но без соответствующего ей объекта в базе.
Поле ЕСТЬ NULL не работает?
Поле регистра сведений, содержащее такую битую ссылку, само по себе не равно NULL. Оно содержит недействительное, но тем не менее, существующее ссылочное значение. Поэтому попытка отбора или проверки ГДЕ Владелец ЕСТЬ NULL не даст нужного результата.
Поле.Ссылка ЕСТЬ NULL работает?
Это ключевой момент. Платформа 1С для битых ссылок имеет такую особенность: если попытаться получить внутреннюю ссылку объекта через синтаксис ПолеССылкой.Ссылка, то для *битой* ссылки это выражение вернет именно NULL. Это позволяет нам эффективно отфильтровывать записи с несуществующими объектами в запросах. Если поле является составным типом, содержащим несколько видов ссылок (например, Справочник.Номенклатура, Документ.ПоступлениеТоваров), условие Поле.Ссылка ЕСТЬ NULL все равно будет работать корректно для определения битых ссылок, независимо от конкретного типа объекта, на который указывала битая ссылка.
Рассмотрим наиболее гибкий и мощный способ удаления таких записей — с использованием программного кода 1С. Этот подход состоит из двух основных шагов: сначала мы находим все записи с битыми ссылками с помощью запроса, а затем в цикле удаляем каждую из них.
Для начала нам нужно получить список всех записей из регистра сведений "Штрихкоды", у которых поле "Владелец" содержит битую ссылку. Мы воспользуемся запросом с условием, которое мы обсудили выше.
Создадим новый запрос и укажем условие Штрихкоды.Владелец.Ссылка ЕСТЬ NULL. Обратите внимание, что мы должны выбрать из запроса все измерения регистра, чтобы потом корректно удалить записи через НаборЗаписей.
Посмотрим на пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Владелец КАК Владелец,
| Штрихкоды.Штрихкод КАК Штрихкод // Обязательно добавляем все измерения регистра
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
|ГДЕ
| Штрихкоды.Владелец.Ссылка ЕСТЬ NULL";
Выборка = Запрос.Выполнить().Выбрать();
В этом запросе мы выбираем не только само поле Владелец, но и Штрихкод, а также любые другие измерения, которые присутствуют в вашем регистре сведений "Штрихкоды". Это критически важно, поскольку при удалении через НаборЗаписей нам потребуется установить отбор по всем измерениям для каждой конкретной записи, которую мы хотим удалить.
Условие Штрихкоды.Владелец.Ссылка ЕСТЬ NULL сработает для всех типов битых ссылок в поле "Владелец", будь то справочник, документ или любой другой ссылочный тип.
НаборЗаписейПолучив выборку из запроса, мы можем приступить к пошаговому удалению каждой найденной записи. Для удаления записей регистра сведений используется объект НаборЗаписей. Мы будем итерировать по выборке, для каждой строки создавать новый НаборЗаписей, устанавливать отбор по значениям измерений текущей строки и затем записывать пустой набор.
Проанализируем шаги:
Пока Выборка.Следующий Цикл для обхода всех найденных битых записей.НаборЗаписей: Для каждой записи мы создаем новый экземпляр НаборЗаписей для нашего регистра: НЗ = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();.
НЗ.Отбор.Владелец.Установить(Выборка.Владелец);
НЗ.Отбор.Штрихкод.Установить(Выборка.Штрихкод); // Добавляем все остальные измерения
// Если регистр имеет другие измерения, их также нужно добавить в отбор:
// НЗ.Отбор.ДругоеИзмерение.Установить(Выборка.ДругоеИзмерение);
Это подтверждается тем, что в дискуссии прозвучала важная мысль: "Объектов в базе нет, но ссылки остались и они разные. Поэтому наборы измерений при создании набора записей будут разные." Это означает, что для каждой битой записи нужно формировать свой уникальный отбор.
НЗ.Записать(). Когда у НаборЗаписей установлен отбор, и сам набор пуст (то есть мы не считывали в него никаких записей из базы), вызов Записать() приведет к удалению всех записей из регистра, которые соответствуют установленному отбору. Это является стандартным способом удаления записей регистра сведений по отбору.Вот полный пример кода для удаления:
// Шаг 1: Идентификация битых ссылок запросом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Владелец КАК Владелец,
| Штрихкоды.Штрихкод КАК Штрихкод // Обязательно добавляем все измерения регистра
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
|ГДЕ
| Штрихкоды.Владелец.Ссылка ЕСТЬ NULL";
Выборка = Запрос.Выполнить().Выбрать();
// Шаг 2: Удаление записей через НаборЗаписей
Пока Выборка.Следующий Цикл
// Создаем новый набор записей для каждой записи из выборки
НЗ = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();
// Устанавливаем отбор по всем измерениям текущей записи
// Это гарантирует, что будет удалена только конкретная запись
НЗ.Отбор.Владелец.Установить(Выборка.Владелец);
НЗ.Отбор.Штрихкод.Установить(Выборка.Штрихкод);
// Если у вас есть другие измерения, добавьте их в отбор:
// НЗ.Отбор.Измерение3.Установить(Выборка.Измерение3);
// НЗ.Отбор.Измерение4.Установить(Выборка.Измерение4);
// Запись пустого набора с установленным отбором фактически удаляет записи,
// соответствующие этому отбору.
НЗ.Записать();
КонецЦикла;
Сообщить("Удаление записей с битыми ссылками завершено.");
Этот код можно поместить в обработку или выполнить в консоли запросов/кода 1С. Перед запуском обязательно сделайте резервную копию базы данных!
Помимо программного подхода, существуют и другие способы, которые могут быть полезны в зависимости от ситуации и объема данных.
Для комплексной проверки и исправления ссылочной целостности базы данных 1С:Предприятие существует встроенный инструмент "Тестирование и исправление" (ТИС). Этот инструмент доступен в режиме "Конфигуратор" через меню "Администрирование".
Рассмотрим шаги использования ТИС:
Использование ТИС является предпочтительным способом для больших баз данных, так как это штатный инструмент, оптимизированный для работы с СУБД, и не требует программирования. Однако перед его использованием всегда рекомендуется создавать резервную копию базы данных.
Если количество записей с битыми ссылками не слишком велико, или вы предпочитаете ручной контроль, можно удалить их непосредственно из формы списка регистра сведений.
Разберем процесс:
Shift+Клик для выделения диапазона или Ctrl+Клик для выборочного выделения.Delete или используйте соответствующую команду в контекстном меню (правая кнопка мыши). Система попросит подтвердить удаление.Этот метод подходит для ситуаций, когда количество битых записей относительно невелико. Для большого объема данных он может быть трудоемким и неэффективным.
При выполнении любых операций по изменению данных в базе 1С, особенно связанных с массовым удалением, следует придерживаться следующих рекомендаций:
Поле.Ссылка ЕСТЬ NULL универсален и работает даже для полей составного типа, содержащих множество ссылочных типов.Мы подробно рассмотрели несколько методов для решения проблемы удаления записей из регистра сведений, где поле с ссылкой имеет значение "Объект не найден". Выбор конкретного метода зависит от объема данных, ваших навыков программирования и доступности инструментария. В большинстве случаев комбинация запроса и удаления через НаборЗаписей является наиболее гибким и эффективным программным решением, а "Тестирование и исправление" – мощным универсальным инструментом.