Профессия — 1С

Рукопашный бой Карташ

Категории

Битые ссылки

рубрики: Разное | Дата: 11 Май, 2017

Сегодня поговорим о причинах возникновении битых ссылок в 1С, их поиске и возможном исправлении. Многие сталкивались с ситуацией, когда в каком-нибудь из реквизитов документа, справочника, регистра и т.д. вместо ожидаемого наименования объекта можно увидеть вот такую надпись:


Это говорит о том, что в поле текущего объекта записана ссылка на какой-то объект базы данных, но физически этого объекта в базе данных не существует.




Как правило это говорит о том, что объект базы данных был удален без предварительной проверки ссылок на него.

Искусственное создание битой ссылки.

Давайте искусственно воспроизведем данную ситуацию. Пусть у нас есть справочник Товары и регистр сведений Цены, в котором хранятся записаны цены товаров. И есть товар Дырокол с соответствующей ценой:


А теперь напишем и выполним процедуру, которая удалит элемент Дырокол из справочника Товары




&НаСервереБезКонтекста
Процедура СоздатьБитуюСсылкуНаСервере()

	СправочникОбъект = Справочники.Товары.НайтиПоНаименованию("Дырокол").ПолучитьОбъект();
	СправочникОбъект.Удалить();

КонецПроцедуры

В результате получаем битую ссылку в регистре сведений Цены


Поэтому, если есть острая необходимость не просто пометить какие-либо объекты на удаление, а программно удалить их насовсем из базы данных, необходимо предварительно выполнить поиск ссылок на эти объекты с помощью функции НайтиПоСсылкам(<МассивСсылок>). В качестве обязательного параметра в эту функцию передается массив со ссылками на проверяемые объекты. Можно также передавать дополнительные параметры, которые позволяют сузить область поиска. Возвращает эта функция таблицу значений со списком объектов, в которых были найдены ссылки на искомые объекты.




Также можно воспользоваться функцией УдалитьОбъекты(<МассивСсылок>), которая удаляет из базы данных объекты, переданные в массиве, но только те на которые не найдено ссылок. А еще лучше пользоваться стандартной схемой удаления объектов из базы данных, т.е. сначала помечать их на удаление, а потом уже удалять окончательно при помощи стандартной обработки, в которую уже встроен контроль ссылочной целостности.

Ситуацию по созданию битой ссылки можно воспроизвести и в пользовательском режиме, без использования программного кода. Это становится возможным, когда у пользователя есть роль в которой для данного типа объекта (в нашем случае это справочник Товары) отмечены права Удаление и одно из следующих прав: Интерактивное удаление, Интерактивное удаление помеченных, Интерактивное удаление предопределенных, Интерактивное удаление помеченных предопределенных.


В этом случае у пользователя появляется возможность не просто установить пометку удаления, а используя горячие клавиши Shift + Delete Удалить объект из базы данных без контроля ссылочной целостности. Поэтому, как правило, эти права отключены даже для администраторов.

Поиск битых ссылок

Допустим, что мы предполагаем наличие битых ссылок в каком-либо объекте. Сразу же возникает вопрос их поиска. Рассмотрим два варианта как это можно сделать программными средствами.

1. С использованием метода ПолучитьОбъект()

Рассмотрим самый простой пример — поиск битых ссылок в реквизите справочника. Пусть в справочнике Товары у нас есть реквизит Поставщик. И есть подозрение, что кто-то удалил поставщика без проверки. Переберем все товары и в каждом товаре проверим поставщика. Суть метода заключается в том, что ссылка у нас есть, а по сути ссылка — это уникальный идентификатор объекта, но самого объекта нет, поэтому метод ПолучитьОбъект() вернет Неопределено.




ВыборкаТовары = Справочники.Товары.Выбрать();

Пока ВыборкаТовары.Следующий() Цикл

	ПоставщикСсылка = ВыборкаТовары.Поставщик;

	Если НЕ ПоставщикСсылка.Пустая() И ПоставщикСсылка.ПолучитьОбъект() = Неопределено Тогда

		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = "Найдена битая ссылка на поставщика в товаре: " + ВыборкаТовары.Наименование;
		Сообщение.Сообщить();

	КонецЕсли;

КонецЦикла;

2. С использованием языка запросов 1С

Сейчас в версиях платформы 1С8 достаточно редко можно встретить код, где как в предыдущем примере выполняется обход всех элементов справочника. Как правило все делается с использованием языка запросов 1С. И поиск битых ссылок не исключение. Их также можно искать при помощи запросов. В этом случае у нас поле Товары.Поставщик.Ссылка будет равно NULL. И плюс надо отсечь товары у которых поставщик просто не заполнен:




Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Товары.Представление КАК Товар
|ИЗ
|	Справочник.Товары КАК Товары
|ГДЕ
|	Товары.Поставщик.Ссылка ЕСТЬ NULL 
|	И Товары.Поставщик <> ЗНАЧЕНИЕ(Справочник.Поставщики.ПустаяСсылка)";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = "Найдена битая ссылка на поставщика в товаре: " + Выборка.Товар;
	Сообщение.Сообщить();

КонецЦикла;

Исправление битых ссылок

Чисто теоретически мы можем программно создать объект с тем же самым уникальным идентификатором который хранится в соответствующем поле записи с битой ссылкой. Немного модифицируем код, где мы искали битую ссылку. Получим запросом ссылку на несуществующий объект, при обходе выборки найдем его уникальный идентификатор и создадим нового поставщика с тем же самым уникальным идентификатором:




Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Товары.Поставщик КАК Поставщик
|ИЗ
|	Справочник.Товары КАК Товары
|ГДЕ
|	Товары.Поставщик.Ссылка ЕСТЬ NULL
|	И Товары.Поставщик <> ЗНАЧЕНИЕ(Справочник.Поставщики.ПустаяСсылка)";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

	УИД = Выборка.Поставщик.УникальныйИдентификатор();
	ПоставщикСсылка	= Справочники.Поставщики.ПолучитьСсылку(УИД);

	ПоставщикОбъект	= Справочники.Поставщики.СоздатьЭлемент();
	ПоставщикОбъект.УстановитьСсылкуНового(ПоставщикСсылка);
	ПоставщикОбъект.Наименование = "ООО Канцтовары";
	ПоставщикОбъект.Записать();

КонецЦикла;

Конечно на практике это вряд ли можно применить, т.к. необходимо будет заполнить все реквизиты вновь созданного объекта, которые нам неизвестны. Этот пример скорее показателен в плане создания объекта с заданным уникальным идентификатором.

Более реалистичным выглядит вариант с восстановлением резервной копии базы данных и переносом из нее удаленных объектов в рабочую базу. В частности можно попытаться сделать это с помощью стандартной обработки с диска ИТС ВыгрузкаЗагрузкаДанныхXML.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

   

2018г. Профессия — 1С. Обмен опытом по программированию в 1С