Объект не найден

  • автор:

1с битая ссылка

Admin 15 августа, 2019

Задача: Найти битые ссылки в справочнике и по возможности восстановить их.

Исходные данные: В справочнике ‘Футбольные клубы’ есть реквизит ‘Спонсор’ – тип ‘СправочникСсылка.Спонсоры’. Какой-то умный пользователь, воспользовался брешью в системе прав доступа и напрямую удалил элемент ‘Газ’ из этого справочника. В итоге имеем такую картину:

<Объект не найден>

Рассмотрим способы, с помощью которых, мы сможем отыскать элементы с битыми ссылками:

  • С помощью запроса. Обращаемся в запросе через ‘точку’ к любым данным нашего битого реквизита ‘Спонсор’. В результате программой будет построено “левое соединение”, для получения этого значения. А как мы знаем, если при соединении таблиц, какие-то данные отсутствуют, то в итоге мы получим ‘NULL’:

1С (Код)

1 2 3 4 5 6 7 ВЫБРАТЬ ФутбольныеКлубы.Ссылка КАК Ссылка, ФутбольныеКлубы.Спонсор.Код КАК Спонсор ИЗ Справочник.ФутбольныеКлубы КАК ФутбольныеКлубы ГДЕ ФутбольныеКлубы.Спонсор.Код Есть NULL

Поиск битых ссылок с помощью запроса.

  • С помощью метода ‘ПолучитьОбъект()‘. В случае если мы пытаемся получить объект битой ссылки, то в итоге получим пустое значение, не принадлежащее ни к одному типу:

1С (Код)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 &НаСервере Процедура НайтиБитыеСсылкиНаСервере() Выборка = Справочники.ФутбольныеКлубы.Выбрать(); Пока Выборка.Следующий() Цикл Если Выборка.Спонсор.ПолучитьОбъект() = Неопределено Тогда Сообщить(Выборка.Наименование); КонецЕсли; КонецЦикла; КонецПроцедуры &НаКлиенте Процедура НайтиБитыеСсылки(Команда) НайтиБитыеСсылкиНаСервере(); КонецПроцедуры

Поиск битых ссылок с метода “ПолучитьОбъект()”.

  • Поиск по строке ‘Объект не найден’. Преобразуем значение реквизита ‘Спонсор’ в строку и ищем вхождение подстроки ‘<Объект не найден>’:

1С (Код)

  • С помощью универсальной функции из конфигурации ‘Библиотека стандартных подсистем’: ‘Функция СсылкаСуществует(ПроверяемаяСсылка)‘:

1С (Код)

Вот такими простыми способами мы можем выявить любые битые ссылки в нашей конфигурации.

Так как же восстановить значение битой ссылки? Для начала нам нужен любой архив нашей рабочей базы, где данные значения еще имеют нормальный (не битый) вид.

Теперь нужно получить уникальный идентификатор битой ссылки, делается это просто:

1С (Код)GUID битой ссылки.

Имея архив базы, GUID и тип данных – мы легко можем получить утерянный элемент:

1С (Код)Найденные ссылки.

С помощью универсальной обработки переноса данных “Выгрузка загрузка данных xml” осуществляем восстановление элемента.

Выгружаем из архива:

Выгрузка данных xml.Выгрузка данных xml.

Загружаем в базу с битой ссылкой:

Загрузка данных.

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

Готово. Элемент жив!

Восстановленный элемент.

Вот так вот просто мы восстановили нашу битую ссылку. С помощью вышеописанных алгоритмов можно восстановить любые битые данные! Естественно при наличии архивов.

1С — поиск и исправление битых ссылок , пример процедуры и запроса

Если в элементе справочника или документа присутствует фраза <Объект не найден>, значит ссылки на этот объект не существует — это так называемая битая ссылка. Если не исправить ситуацию, то возникнут сложности при обмене данными. Пример исправления ситуации ниже.

Задача:

  1. найти в справочнике «Договоры» все договоры, с битыми ссылками на владельца (контрагента);
  2. заменить битые ссылки на действующего контрагента;

Пример процедуры:

&НаСервере Процедура ЗаменитьБитыеСсылкиНаСервере() Запрос = Новый Запрос( «ВЫБРАТЬ | ДоговорыКонтрагентов.Ссылка КАК ДоговорСсылка, | ДоговорыКонтрагентов.Владелец КАК КонтрагентСсылка |ИЗ | Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов»); Выборка = Запрос.Выполнить().Выбрать(); Пока Выборка.Следующий() Цикл Если Выборка.КонтрагентСсылка.ПолучитьОбъект() = Неопределено Тогда //если контрагент не определен, значит — это битая ссылка ДоговорОбъект = Выборка.ДоговорСсылка.ПолучитьОбъект(); ДоговорОбъект.Владелец = Справочники.Контрагенты.НайтиПоКоду(«ФР-001289», Истина); ДоговорОбъект.Записать(); Сообщить(«Исправлен договор: » + ДоговорОбъект.Код); КонецЕсли; КонецЦикла; КонецПроцедуры

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

Данная ситуация вполне типичная и почти каждый пользователь платформы 1С:Предприятие сталкивался с такой битой ссылкой* («Объект не найден») хотя бы раз.

Предупреждение: Перед тем, как приступать к каким-либо манипуляциям с базой данных 1С, необходимо сделать ее резервную копию. Чтобы сделать резервную копию информационной базы данных можно воспользоваться командой «Выгрузить информационную базу» в конфигураторе, сделать резервную копию из режима 1С:Предприятия или скопировать папку с самой информационной базой на съемный носитель / в другое место.

Теперь перейдем непосредственно к решению проблемы несуществующих объектов.Первое, что необходимо сделать – это разобраться в причине возникновения таких объектов.

Причины могут быть разные, в каждом случае требуется особый подход для решения проблемы и восстановления целостности данных. Рассмотрим основные из них.

  • 1. Непосредственное удаление объектов без пометки на удаление и контроля ссылочной целостности

В программе 1С:Предприятие при стандартном удалении объектов производится контроль ссылочной целостности, предусматривающий удаление объекта в два этапа:

1) установка пометки на удаление;

2) удаление стандартной процедурой с контролем ссылочной целостности.

Однако этот механизм можно обойти, имея право непосредственного удаления объектов без пометки на удаление и контроля ссылочной целостности (в правах пользователя – право «Интерактивное удаление»). Такое удаление производится сочетанием клавиш «SHIFT + DELETE». В результате непосредственного удаления ссылка на объект становится битой и при ее наличии в других объектах отображается как «Объект не найден».

Решение:

Восстановить объект в этой базе невозможно, поэтому можно воспользоваться одним из способов:

  • При наличии резервных копий информационной базы восстановить последнюю (если она была сделана недавно и от текущей она не отличается) и работать в ней;
  • Если пользователь знает, какой объект был удален: найти копию базы, где присутствует этот объект, воспользоваться обработкой «Выгрузка и загрузка данных XML», которая находится в свободном доступе в интернете, перенести объект из старой базы в новую с помощью данной обработки. Битые ссылки заменятся этим объектом. Если неизвестно, какой объект был удален – можно найти его по уникальному идентификатору в старой базе и перенести его обработкой «Выгрузка и загрузка данных XML».

Рекомендации:

Чтобы избежать таких ошибок в дальнейшем, как вариант – запретить пользователям интерактивное удаление. Также необходимо обеспечить регулярное резервное копирование Информационной базы 1С: Предприятие, чтобы всегда иметь возможность восстановить поврежденные или удаленные данные.

  • 2. Объект из другой базы. Имеет место обмен с другой информационной базой (Стандартный обмен, обмен в Распределенной информационной базе «РИБ», Универсальный обмен)
  • 2.1 Объект не был выгружен из базы – источника

Решение

В этом случае можно выгрузить объект из Базы – Источника заново, в результате чего этот объект заменит собой все пустые ссылки.

Используем в качестве примера обмен между базами: 1С: Управление торговлей 11.2 и 1С: Бухгалтерия Предприятия 3.0.

При выгрузке документа реализации номенклатура из табличной части не выгрузилась в Бухгалтерию Предприятия. Такое могло произойти при ошибочном снятии объектов справочника «Номенклатура» с регистрации к обмену, либо при нарушении последовательности обмена между базами.

Если таких объектов немного, можно найти их в базе-источнике и зарегистрировать к обмену еще раз (например, написать комментарий к объекту и сохранить изменения, тогда он зарегистрируется к обмену автоматически и выгрузится при следующей синхронизации данных).

Также можно зарегистрировать объекты к выгрузке через стандартную обработку «Регистрация изменений для обмена данными». Для этого нужно из списка настроенных синхронизаций данных сначала найти обмен с базой, в которой есть ненайденные объекты, затем выбрать «Состав отправляемых данных» (или найти обработку «Регистрация изменений для обмена данными» во «Всех функциях»).

В обработке нужно выбрать необходимые объекты в дереве с помощью флажков и зарегистрировать:

– все объекты выбранных типов – можно выбрать объект и все его подчиненные объекты;

– объекты выбранных типов с авторегистрацией;

– одиночные объекты (выбрать из списка);

– объекты при помощи отбора (задать отбор для элементов).

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

В результате обмена данными ссылки восстановятся.

Рекомендации:

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

  • 2.2 Распределенная информационная база «РИБ».

Объект был удален

Из периферийной информационной базы в Центральную выгрузили объект с пометкой на удаление, а затем сняли ее. В Центральной базе объект с пометкой был удален, а затем выгружен в периферийную как «Объект не найден».

Решение

Как и при непосредственном удалении без контроля ссылочной целостности, в этом случае можно воспользоваться восстановлением объекта из резервной копии базы данных посредством обработки «Выгрузка и загрузка данных XML» (поставляется в составе конфигурации “Конвертация данных, редакция 2” и находится в свободном доступе в Интернете).

ТЕСТИРОВАНИЕ И ИСПРАВЛЕНИЕ ИНФОРМАЦИОННОЙ БАЗЫ 1С

Если данный объект не нужно восстанавливать, то необходимо удалить все ссылки на него посредством стандартного функционала 1С.

Для удаления ссылок на несуществующие объекты можно воспользоваться тестированием и исправлением информационной базы (предварительно сделав резервную копию базы). Для этого необходимо зайти в Конфигуратор – Администрирование – Тестирование и исправление.

В новом окне появятся несколько вариантов проверок и режимов, которые необходимо выбрать.

Реиндексация таблиц информационной базы – это перестроение индексов таблиц базы данных. В информационной базе строится индекс для ускорения поиска по определенным реквизитам. Эта операция приводит к ускорению и оптимизации работы информационной базы, поэтому рекомендуется выполнять ее хотя бы раз в месяц.

Проверка логической целостности информационной базы – проверка логической целостности базы (связи между таблицами базы данных) и исправление ошибок в структурах таблиц информационной базы.

Проверка ссылочной целостности информационной базы – проверка тех самых ссылок на несуществующие объекты в базе данных.

Необходимо выбрать один из трех вариантов исправления таких ошибок:

Создавать объекты – система создает элементы, которые потом нужно заполнить;

Очищать ссылки – ссылки будут очищены;

Не изменять – будут показаны ошибки, ссылки не изменятся.

Пересчет итогов – пересчет предварительных результатов в регистрах накопления, расчета и бухгалтерии (Срез Последних, Остатки, Обороты, Остатки и обороты и т.д). Пересчет итогов также приводит к ускорению и оптимизации работы информационной базы.

Сжатие таблиц информационной базы– уменьшение размера базы после тестирования за счет удаления информации об уже удаленных объектах из базы данных.

Реструктуризация таблиц информационной базы – создание идентичных таблиц базы данных и перенос имеющихся данных в изменённые таблицы.

В нашем случае выставим все галочки. После установки настроек нажать «Выполнить» и ждать окончания процедуры. Результаты тестирования можно увидеть в окне служебных сообщений конфигуратора 1С.

После окончания тестирования вопрос с несуществующими объектами будет решен.

Рекомендации:

При удалении объектов и снятии с них пометки на удаление проверять их наличие в других базах. Регулярно выполнять тестирование и исправление информационной базы 1С.

2.3 «Объект не найден» после Универсального обмена данными

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

Фирма «1С» активно развивает формат EnterpriseData и его использование во все большем количестве приложений.

При таком обмене иногда могут возникать ошибки, связанные с конвертацией объектов одного типа (базы – источника) в объекты другого типа (базы – приемника).

Например, при обмене между базами 1С: Управление торговлей 11.2 и 1С: Бухгалтерия Предприятия 3.0. документ «Передача товаров между организациями» из «Управление торговлей» переносится в «Бухгалтерию Предприятия» как Документ «Поступление (акт, накладная)» или Документ «Реализация (акт, накладная)». При этом одна организация переносится в «Бухгалтерию Предприятия» как контрагент. Данное преобразование предусмотрено фирмой «1С» в правилах конвертации данных. Но, несмотря на это, иногда происходят ошибки при переносе разнотипных объектов между базами. Это может быть вызвано долгим отсутствием обновления какой-либо базы – участника обмена и как следствие – старыми правилами формата обмена, которые не гарантируют правильного переноса данных.

Решение

Обновить обе базы до последних релизов и зарегистрировать невыгруженные объекты к обмену. После обмена данными с использованием последней версии формата обмена объекты должны конвертироваться и переноситься без ошибок.

Используемую версию формата можно изменить в настройках обмена на вкладке «Служебная информация»:

Если после этих действий ссылки «Объект не найден» не были заменены правильными объектами, необходимо настроить сопоставление данных вручную.

Для этого нам понадобится регистр «Публичные идентификаторы синхронизируемых объектов» (Найти его можно через «Все функции» – «Регистры сведений». Он используется для сопоставления объектов при синхронизации через универсальный формат. Ввиду большого количества записей открытие регистра может занять продолжительное время.

Регистр имеет следующую структуру:

В регистре можно обнаружить ссылки на несуществующие объекты:

В первом столбце находятся идентификаторы объектов из другой информационной базы. По этому идентификатору можно найти объект в базе-источнике.

Как получить ссылку на любой элемент информационной базы 1С:

В 1С есть очень полезный функционал – можно получить ссылку на любой объект базы и также перейти к объекту.

Ссылки, представленные во второй колонке регистра, не были найдены в базе, соответственно, эти объекты не были созданы.

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

В нашем примере битые ссылки находятся в документе «Реализация товаров». Вместо контрагента <Объект не найден> (18:805910bf4888a98211e4f89df8b22aab). Находим этот документ в базе-источнике и определяем Организацию, которую необходимо перенести в качестве контрагента. Затем ищем такого же контрагента в базе-приемнике, при его отсутствии – создаем.

После создания или нахождения нужного объекта в ИБ нужно задать сопоставление в регистре «Публичные идентификаторы синхронизируемых объектов». Находим строку, содержащую битую ссылку <Объект не найден> (18:805910bf4888a98211e4f89df8b22aab) и сопоставляем ей необходимого контрагента. В примере: объект с идентификатором «f8b22aab-f89d-11e4-8059-10bf4888a982» будет выгружен в базу как «Моя Организация» в не зависимости от типа объекта источника. В базе – источнике необходимо зарегистрировать такие объекты к обмену заново и запустить синхронизацию данных. После обмена не найденные объекты заменятся согласно сопоставлениям, сделанным в регистре.

При большом количестве битых ссылок рекомендуем обратиться к проверенным специалистам, которые восстановят Ваши данные без потерь.

Рекомендации:

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

Поиск в базе битых ссылок — объект не найден

В статье мы обсуждали как востановить битые ссылки!
А вот как найти в базе все битые ссылки, которые имеют вид типа «<Объект не найден> (137:8b270030482898d011daad3cc45fc830)»?
Для поиска этого была написана данная обработка: Скачивать файлы может только зарегистрированный пользователь!
Для поиска: Выбираем объекты метаданных , которые хотим проверить, жмем кнопочку «Выполнить» и наблюдаем в таблице выходные данные. Откуда можем попасть в объекты-источники.

Для программиста:
Код 1C v 8.х Процедура КнопкаВыполнитьНажатие(Кнопка)
ИспользоватьОграничение = ЗначениеЗаполнено(ОграничениеТипов);
РезультатПоиска.Очистить();
Для Каждого ОбъектыМетаданных Из КоллекцияОбъектов Цикл
Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
Состояние(ОбъектМетаданных.ПолноеИмя());
ПроверитьОбъектНаБитыеСсылки(ОбъектМетаданных);
КонецЦикла;
КонецЦикла;
Для Каждого ОбъектыМетаданных Из КоллекцияРегистров Цикл
Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
Состояние(ОбъектМетаданных.ПолноеИмя());
ПроверитьРегистрНаБитыеСсылки(ОбъектМетаданных);
КонецЦикла;
КонецЦикла;
//Анализ последовательностей
//ПроверитьОбъектНаБитыеСсылки(Метаданные.Справочники.СотрудникиОрганизаций);
КонецПроцедуры
Процедура ВывестиДанные(ТекстЗапроса)
Запрос = Новый Запрос(ТекстЗапроса);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
ТЗ = РезультатЗапроса.Выгрузить();
Для Каждого Стр Из ТЗ Цикл
ОбработкаПрерыванияПользователя();
Строка = РезультатПоиска.Добавить();
ЗаполнитьЗначенияСвойств(Строка, Стр);
КонецЦикла;
КонецЕсли;
Исключение
Сообщить(ИнформацияОбОшибке().Описание + » » + ИнформацияОбОшибке().Причина);
КонецПопытки;
КонецПроцедуры
Процедура ПроверитьРегистрНаБитыеСсылки(ОбъектМетаданных)
ИмяТаблицы = ОбъектМетаданных.ПолноеИмя();
Если Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных) Тогда
Если ОбъектМетаданных.РежимЗаписи = НезависимыйРежимЗаписи Тогда
//АнализСвойствРегистраСведений(ОбъектМетаданных, ОбъектМетаданных.Измерения, ИмяТаблицы);
//АнализСвойствРегистраСведений(ОбъектМетаданных, ОбъектМетаданных.Ресурсы, ИмяТаблицы);
//АнализСвойствРегистраСведений(ОбъектМетаданных, ОбъектМетаданных.Реквизиты, ИмяТаблицы);
Возврат;
КонецЕсли;
АнализСвойствРегистра(ОбъектМетаданных, ОбъектМетаданных.Реквизиты, ИмяТаблицы);
КонецЕсли;
АнализСвойствРегистра(ОбъектМетаданных, ОбъектМетаданных.Измерения, ИмяТаблицы);
АнализСвойствРегистра(ОбъектМетаданных, ОбъектМетаданных.Реквизиты, ИмяТаблицы);
АнализРегистратораРегистра(ОбъектМетаданных, ИмяТаблицы);
Если Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Тогда
//Для рег. бухгалтерии анализ субконто
КонецЕсли;
Если Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Тогда
//Для регистров расчета доп. анализ
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьОбъектНаБитыеСсылки(ОбъектМетаданных)
ИмяТаблицы = ОбъектМетаданных.ПолноеИмя();
АнализСвойствОбъекта(ОбъектМетаданных, ОбъектМетаданных.Реквизиты, ИмяТаблицы);
Для Каждого ТабЧасть Из ОбъектМетаданных.ТабличныеЧасти Цикл
Если ТабличныеЧастиИсключения.Найти(ТабЧасть.Имя) <> Неопределено Тогда
Продолжить;
КонецЕсли;
АнализСвойствОбъекта(ОбъектМетаданных, ТабЧасть.Реквизиты, ИмяТаблицы + «.» + ТабЧасть.Имя)
КонецЦикла;
//проверка владельца у справочников
Если Метаданные.Справочники.Содержит(ОбъектМетаданных) И ОбъектМетаданных.Владельцы.Количество() > 0 Тогда
МассивВладельцев = Новый Массив;
Для Каждого Элемент Из ОбъектМетаданных.Владельцы Цикл
МассивВладельцев.Добавить(Элемент);
КонецЦикла;
//АнализСвойствВладельцаОбъекта(ОбъектМетаданных, МассивВладельцев, ИмяТаблицы);

КонецЕсли;
//Для задач поле исполнитель
//проверки в журналах
ОбработкаПрерыванияПользователя();
КонецПроцедуры
Процедура АнализСвойствОбъекта(ОбъектМетаданных, Свойства, ИмяТаблицы)
Для Каждого Реквизит Из Свойства Цикл
Если РеквизитыИсключения.Найти(Реквизит.Имя) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого моТип Из Реквизит.Тип.Типы() Цикл
ТекстЗапроса = «»;
МетаданныеТипа = Метаданные.НайтиПоТипу(моТип);
Если МетаданныеТипа <> Неопределено
И Не Метаданные.Перечисления.Содержит(МетаданныеТипа) Тогда
Если ИспользоватьОграничение Тогда
Если Не ПоискПоТипу(МетаданныеТипа.ПолноеИмя()) Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
ДобавитьВЗапросОбъект(ТекстЗапроса, ОбъектМетаданных, ИмяТаблицы, Реквизит.Имя, моТип);
КонецЕсли;
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ВывестиДанные(ТекстЗапроса);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура АнализСвойствРегистра(ОбъектМетаданных, Свойства, ИмяТаблицы)
Для Каждого Реквизит Из Свойства Цикл
Если РеквизитыИсключения.Найти(Реквизит.Имя) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого моТип Из Реквизит.Тип.Типы() Цикл
ТекстЗапроса = «»;
МетаданныеТипа = Метаданные.НайтиПоТипу(моТип);
Если МетаданныеТипа <> Неопределено
И Не Метаданные.Перечисления.Содержит(МетаданныеТипа) Тогда
Если ИспользоватьОграничение Тогда
Если Не ПоискПоТипу(МетаданныеТипа.ПолноеИмя()) Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
ДобавитьВЗапросРегистр(ТекстЗапроса, ОбъектМетаданных, ИмяТаблицы, Реквизит.Имя, моТип);
КонецЕсли;
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ВывестиДанные(ТекстЗапроса);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура АнализРегистратораРегистра(ОбъектМетаданных, ИмяТаблицы)
МассивРегистраторов = ПолучитьСписокРегистраторов(ОбъектМетаданных);
Для Каждого Регистратор Из МассивРегистраторов Цикл
Если РеквизитыИсключения.Найти(«Регистратор») <> Неопределено Тогда
Продолжить;
КонецЕсли;
моТип = Регистратор;
ТекстЗапроса = «»;
МетаданныеТипа = Метаданные.НайтиПоТипу(моТип);
Если МетаданныеТипа <> Неопределено
И Не Метаданные.Перечисления.Содержит(МетаданныеТипа) Тогда
Если ИспользоватьОграничение Тогда
Если Не ПоискПоТипу(МетаданныеТипа.ПолноеИмя()) Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
ДобавитьВЗапросРегистр(ТекстЗапроса, ОбъектМетаданных, ИмяТаблицы, «Регистратор», моТип);
КонецЕсли;
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ВывестиДанные(ТекстЗапроса);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция ПолучитьСписокРегистраторов(ОбъектМетаданных)
МассивРегистраторов = Новый Массив;
МенеджерОбъект = ПолучитьМенеджерОбъекта(ОбъектМетаданных);
Если МенеджерОбъект <> Неопределено Тогда
НаборЗаписей = МенеджерОбъект.СоздатьНаборЗаписей();
ЭлементОтбора = НаборЗаписей.Отбор.Регистратор;
МассивРегистраторов = ЭлементОтбора.ТипЗначения.Типы();
КонецЕсли;
Возврат МассивРегистраторов;
КонецФункции
Функция ПолучитьМенеджерОбъекта(ОбъектМетаданных)
Перем МенеджерОбъекта;
Если Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Тогда
МенеджерОбъекта = РегистрыБухгалтерии;
ИначеЕсли Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных) Тогда
МенеджерОбъекта = РегистрыНакопления;

ИначеЕсли Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных) Тогда
МенеджерОбъекта = РегистрыСведений;
ИначеЕсли Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Тогда
МенеджерОбъекта = РегистрыРасчета;
КонецЕсли;
Возврат МенеджерОбъекта;
КонецФункции
Функция ПоискПоТипу(ИмяТипа)
Результат = Ложь;
Если ИспользоватьОграничение Тогда
МассивСтрок = ОграничениеТипов.НайтиСтроки(Новый Структура(«ТипДанных», ИмяТипа));
Если ЗначениеЗаполнено(МассивСтрок) Тогда
Результат = Истина;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Процедура ДобавитьВЗапросРегистр(ТекстЗапроса, ОбъектМетаданных, ИмяТаблицы, ИмяРеквизита, ТипРеквизита)
Текст = «ВЫБРАТЬ Об.» + ИмяРеквизита + » КАК Объект,
| «»» + ИмяТаблицы + «.» + ИмяРеквизита + «»» КАК ТаблицаИсточник,
| Об.Регистратор КАК ОбъектИсточник,
| » + ДобавитьОписаниеТипа(ИмяРеквизита, ТипРеквизита) + «
|ИЗ
| » + ИмяТаблицы + » КАК Об
|ГДЕ » + ДобавитьУсловия(ИмяРеквизита, ТипРеквизита);
ТекстЗапроса = ТекстЗапроса + ?(ПустаяСтрока(ТекстЗапроса), «», Символы.ПС + «ОБЪЕДИНИТЬ ВСЕ» + Символы.ПС) + Текст;
КонецПроцедуры
Процедура ДобавитьВЗапросОбъект(ТекстЗапроса, ОбъектМетаданных, ИмяТаблицы, ИмяРеквизита, ТипРеквизита)
Текст = «ВЫБРАТЬ Об.» + ИмяРеквизита + » КАК Объект,
| «»» + ИмяТаблицы + «.» + ИмяРеквизита + «»» КАК ТаблицаИсточник,
| Об.Ссылка КАК ОбъектИсточник,
| » + ДобавитьОписаниеТипа(ИмяРеквизита, ТипРеквизита) + «
|ИЗ
| » + ИмяТаблицы + » КАК Об
|ГДЕ » + ДобавитьУсловия(ИмяРеквизита, ТипРеквизита);
ТекстЗапроса = ТекстЗапроса + ?(ПустаяСтрока(ТекстЗапроса), «», Символы.ПС + «ОБЪЕДИНИТЬ ВСЕ» + Символы.ПС) + Текст;
КонецПроцедуры
Функция ДобавитьУсловия(ИмяРеквизита, ТипРеквизита)
мдОбъекта = Метаданные.НайтиПоТипу(ТипРеквизита);
ИмяТаблицы = мдОбъекта.ПолноеИмя();
ПроверкаНаПустыеЗначения = » Об.» + ИмяРеквизита + » ССЫЛКА » + ИмяТаблицы;
ПроверкаНаПустыеЗначения = ПроверкаНаПустыеЗначения + » И ВЫРАЗИТЬ(Об.» + ИмяРеквизита + » КАК » + ИмяТаблицы + «).Ссылка есть null»;
Если Не Метаданные.Перечисления.Содержит(мдОбъекта) Тогда
ПроверкаНаПустыеЗначения = ПроверкаНаПустыеЗначения + » И Об.» + ИмяРеквизита + » <> Значение(» + ИмяТаблицы + «.ПустаяСсылка)»;
КонецЕсли;
Возврат ПроверкаНаПустыеЗначения;
КонецФункции
Функция ДобавитьОписаниеТипа(ИмяРеквизита, ТипРеквизита)
ОбъектТипа = Метаданные.НайтиПоТипу(ТипРеквизита);
ИмяТаблицы = ОбъектТипа.ПолноеИмя();
ОписаниеТипа = «»»» + ИмяТаблицы + «»» КАК ТипДанных»;
Возврат ОписаниеТипа;
КонецФункции
Процедура ОграничениеТиповТипДанныхНачалоВыбора(Элемент, СтандартнаяОбработка)
Перем ЭлементСписка;
СтандартнаяОбработка = Ложь;
Строка = ЭлементыФормы.ОграничениеТипов.ТекущиеДанные;
Если Не ПустаяСтрока(Строка.ТипДанных) Тогда
ЭлементСписка = СписокТипов.НайтиПоЗначению(Строка.ТипДанных);
КонецЕсли;
ВыбранныйЭлемент = СписокТипов.ВыбратьЭлемент( , ЭлементСписка);
Если ВыбранныйЭлемент <> Неопределено Тогда
Строка.ТипДанных = ВыбранныйЭлемент.Значение;
КонецЕсли;
КонецПроцедуры
РеквизитыИсключения = Новый Массив;
ТабличныеЧастиИсключения = Новый Массив;
СписокТипов = Новый СписокЗначений;
Для Каждого ОбъектМетаданных Из Метаданные.Справочники Цикл

СписокТипов.Добавить(ОбъектМетаданных.ПолноеИмя(), ОбъектМетаданных.Имя, , БиблиотекаКартинок.СправочникОбъект);
КонецЦикла;
Для Каждого ОбъектМетаданных Из Метаданные.Документы Цикл
СписокТипов.Добавить(ОбъектМетаданных.ПолноеИмя(), ОбъектМетаданных.Имя, , БиблиотекаКартинок.ДокументОбъект);
КонецЦикла;
КоллекцияОбъектов = Новый Массив;
КоллекцияОбъектов.Добавить(Метаданные.ПланыОбмена);
КоллекцияОбъектов.Добавить(Метаданные.Справочники);
КоллекцияОбъектов.Добавить(Метаданные.Документы);
КоллекцияОбъектов.Добавить(Метаданные.ПланыВидовХарактеристик);
КоллекцияОбъектов.Добавить(Метаданные.ПланыСчетов);
КоллекцияОбъектов.Добавить(Метаданные.ПланыВидовРасчета);
КоллекцияОбъектов.Добавить(Метаданные.БизнесПроцессы);
КоллекцияОбъектов.Добавить(Метаданные.Задачи);
КоллекцияРегистров = Новый Массив;
КоллекцияРегистров.Добавить(Метаданные.РегистрыСведений);
КоллекцияРегистров.Добавить(Метаданные.РегистрыНакопления);
КоллекцияРегистров.Добавить(Метаданные.РегистрыБухгалтерии);
КоллекцияРегистров.Добавить(Метаданные.РегистрыРасчета);

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

Битые ссылки

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

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

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

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

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

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

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

&НаСервереБезКонтекста Процедура СоздатьБитуюСсылкуНаСервере() СправочникОбъект = Справочники.Товары.НайтиПоНаименованию(«Дырокол»).ПолучитьОбъект(); СправочникОбъект.Удалить(); КонецПроцедуры

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

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

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

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

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

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

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

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

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

ВыборкаТовары = Справочники.Товары.Выбрать(); Пока ВыборкаТовары.Следующий() Цикл ПоставщикСсылка = ВыборкаТовары.Поставщик; Если НЕ ПоставщикСсылка.Пустая() И ПоставщикСсылка.ПолучитьОбъект() = Неопределено Тогда Сообщение = Новый СообщениеПользователю; Сообщение.Текст = «Найдена битая ссылка на поставщика в товаре: » + ВыборкаТовары.Наименование; Сообщение.Сообщить(); КонецЕсли; КонецЦикла;

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

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

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

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

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

Запрос = Новый Запрос; Запрос.Текст = «ВЫБРАТЬ | Товары.Поставщик КАК Поставщик |ИЗ | Справочник.Товары КАК Товары |ГДЕ | Товары.Поставщик.Ссылка ЕСТЬ NULL | И Товары.Поставщик <> ЗНАЧЕНИЕ(Справочник.Поставщики.ПустаяСсылка)»; Результат = Запрос.Выполнить(); Выборка = Результат.Выбрать(); Пока Выборка.Следующий() Цикл УИД = Выборка.Поставщик.УникальныйИдентификатор(); ПоставщикСсылка = Справочники.Поставщики.ПолучитьСсылку(УИД); ПоставщикОбъект = Справочники.Поставщики.СоздатьЭлемент(); ПоставщикОбъект.УстановитьСсылкуНового(ПоставщикСсылка); ПоставщикОбъект.Наименование = «ООО Канцтовары»; ПоставщикОбъект.Записать(); КонецЦикла;

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

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

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

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