При разработке расширений для конфигураций на базе БСП (Библиотека Стандартных Подсистем) мы часто сталкиваемся с задачей подключения типовых механизмов к новым объектам. Одна из таких задач — включение контроля дублей для нового справочника. Казалось бы, достаточно поставить галочки и внедрить код, но на практике возникает ошибка "Неверный идентификатор: пустая ссылка типа Идентификатор объекта метаданных".
В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно зарегистрировать объекты расширения в справочниках идентификаторов и как программно подключить поиск и запрет дублей.
Рассмотрим ситуацию: мы создали в расширении справочник МаркиАвтомобилей. Мы хотим использовать типовую обработку "Поиск и удаление дублей". При попытке запуска обработки или выполнения кода поиска мы получаем сообщение об ошибке, содержащее следующий стек вызовов:
Ошибка при выполнении функции ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору.
Неверный идентификатор: пустая ссылка типа "Идентификатор объекта метаданных".
...
{Справочник.ИдентификаторыОбъектовМетаданных.МодульМенеджера(830)}: ОбъектыМетаданных = ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, ВызыватьИсключение);
В чем суть проблемы? Механизмы БСП не работают с объектами метаданных (справочниками, документами) напрямую через Метаданные.Справочники... во всех местах. Для хранения настроек и ссылок БСП использует специальные служебные справочники:
ИдентификаторыОбъектовМетаданных — для объектов основной конфигурации.ИдентификаторыОбъектовРасширений — для объектов, добавленных в расширениях.Ошибка "Неверный идентификатор" означает, что БСП пытается найти ссылку на описание вашего справочника в этих служебных таблицах, но не находит её (или находит пустую/битую ссылку). Это происходит потому, что после добавления объекта в конфигураторе, данные в режиме "Предприятие" еще не обновились.
Самое первое действие при появлении таких ошибок — актуализация служебных справочников. Для объектов расширения это справочник ИдентификаторыОбъектовРасширений.
Рассмотрим способы, как это сделать:
Способ А: Через параметры запуска (Рекомендуемый)
Запустите «1С:Предприятие» с ключом, который инициирует принудительное обновление:
/C ЗапуститьОбновлениеИдентификаторовОбъектовРасширений
Или на английском:
/C RunUpdateExtensionObjectIdentifiers
Способ Б: Программный вызов
Если у вас есть доступ к консоли кода или внешней обработке, выполните следующую команду:
Справочники.ИдентификаторыОбъектовРасширений.ОбновитьДанные();
После выполнения этой процедуры ваш справочник МаркиАвтомобилей корректно пропишется в служебных таблицах БСП, и функции общего назначения смогут получать его идентификатор без ошибок.
Даже если ошибка идентификатора уйдет, обработка "Поиск и удаление дублей" может "не видеть" ваш справочник в списке доступных для поиска. БСП нужно явно сообщить, что в этом справочнике можно искать дубли.
Для этого в расширении нам необходимо переопределить логику общего модуля ПоискИУдалениеДублейПереопределяемый. Посмотрим, как это сделать правильно:
ПоискИУдалениеДублейПереопределяемый.ПриОпределенииОбъектовСПоискомДублей.Код в модуле расширения будет выглядеть так:
&После("ПриОпределенииОбъектовСПоискомДублей")
Процедура Расш1_ПриОпределенииОбъектовСПоискомДублей(Объекты)
// Регистрируем наш справочник из расширения
Объекты.Добавить(Метаданные.Справочники.МаркиАвтомобилей);
КонецПроцедуры
Теперь стандартная обработка будет знать о существовании вашего справочника и позволит пользователю выбирать его для анализа.
Автор темы также задавал вопрос: "Также нужно реализовать запрет на создание элементов с похожим названием, как это сделать?".
Чтобы система проверяла наличие дублей прямо в момент создания новой карточки, нам нужно внести изменения в модуль объекта самого справочника МаркиАвтомобилей (в расширении).
Разберем алгоритм:
ПередЗаписью.Внутри события мы будем обращаться к экспортным методам модуля ПоискИУдалениеДублей. В актуальных версиях БСП (3.x) код выглядит примерно так:
&После("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ)
// Если уже есть Отказ или это загрузка данных - проверку не делаем
Если Отказ Или ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Параметры поиска дублей
ПараметрыПоиска = ПоискИУдалениеДублей.ПараметрыПоискаДублей(Метаданные());
// Указываем правило поиска (например, по наименованию)
// Важно: правило должно быть предварительно настроено или задано здесь программно
// Выполняем проверку
НайденоДублей = ПоискИУдалениеДублей.НайтиДубли(ЭтотОбъект, ПараметрыПоиска);
Если НайденоДублей.Количество() > 0 Тогда
// Здесь логика: либо запретить запись, либо предупредить
ТекстСообщения = "Найдены похожие элементы: " + Символы.ПС;
Для Каждого СтрокаДубля Из НайденоДублей Цикл
ТекстСообщения = ТекстСообщения + СтрокаДубля.Ссылка + Символы.ПС;
КонецЦикла;
ОбщегоНазначения.СообщитьПользователю(ТекстСообщения);
// Если нужен жесткий запрет:
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Важное замечание про нечеткий поиск:
Если вы хотите, чтобы поиск находил не только полные совпадения (например, "Audi" и "Audi"), но и похожие ("Audi" и "Ауди"), вам потребуется использование Полнотекстового поиска. Для этого:
Для корректной работы БСП с объектами расширения необходимо соблюдать последовательность:
Справочники.ИдентификаторыОбъектовРасширений.ОбновитьДанные(), чтобы избавиться от ошибок типа "Неверный идентификатор".ПриОпределенииОбъектовСПоискомДублей, добавив туда ваш справочник.ПоискИУдалениеДублей в событии ПередЗаписью вашего справочника.