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