Разработка и Конфигурация · 11 мин
Как получить элемент справочника 1С программно
Как программно получить элемент справочника в 1С: НайтиПоКоду, НайтиПоНаименованию, ПолучитьСсылку, запросы. Примеры кода, проверка результата и типичные ошибки.
Задача получить ссылку на элемент справочника встречается в коде 1С постоянно: при записи документов, обмене данными, заполнении реквизитов по умолчанию. Платформа предлагает несколько методов — через код, наименование, реквизит, уникальный идентификатор или запрос — и выбор конкретного зависит от того, что известно об искомом элементе и насколько критична скорость выполнения.
Ключевой принцип: почти всегда нужна именно ссылка на элемент, а не объект. Ссылка — лёгкий указатель, который можно присвоить реквизиту документа без чтения данных из базы. Объект же загружает все данные элемента и нужен только тогда, когда вы собираетесь изменять элемент или читать его табличные части.
Какие методы поиска доступны и когда их применять
Менеджер справочника (объект вида Справочники.Номенклатура) предоставляет встроенные методы поиска. Каждый из них выполняет обращение к базе данных и возвращает либо ссылку на найденный элемент, либо пустую ссылку, если ничего не найдено.
| Метод | Что ищет | Когда использовать |
|---|---|---|
| НайтиПоКоду() | Элемент по значению кода | Код уникален и известен, например при обмене по коду |
| НайтиПоНаименованию() | Элемент по наименованию | Известно точное наименование; рискованно при неуникальных названиях |
| НайтиПоРеквизиту() | Элемент по значению реквизита | Поиск по ИНН, артикулу и другим индексированным реквизитам |
| ПолучитьСсылку() | Элемент по уникальному идентификатору | GUID известен из внешней системы или хранится в параметре |
| Запрос | Элементы по произвольным условиям | Сложные отборы, поиск по нескольким полям, выбор множества элементов |
Важное ограничение: НайтиПоКоду и НайтиПоНаименованию работают эффективно, потому что код и наименование индексированы платформой. НайтиПоРеквизиту будет быстрым только если реквизит проиндексирован (в свойствах реквизита установлено индексирование), иначе поиск на большом справочнике может выполняться заметно медленно.
Как выбрать метод
Поиск элемента по коду
Метод НайтиПоКоду принимает значение кода и необязательные параметры: признак поиска по полному коду (для иерархических справочников с сериями кодов), ссылку на родителя и владельца. Метод возвращает ссылку на первый найденный элемент.
ЭлементСсылка = Справочники.Номенклатура.НайтиПоКоду("00-000123");
Если ЭлементСсылка.Пустая() Тогда
Сообщить("Элемент с кодом 00-000123 не найден");
Иначе
Сообщить("Найден: " + ЭлементСсылка);
КонецЕсли;
Обратите внимание на тип кода. Если код справочника числовой, передавайте число, а не строку: НайтиПоКоду(123). Если код строковый с лидирующими нулями, строку нужно передавать в том же формате, в каком она хранится, иначе поиск не сработает. Для подчинённых справочников обязательно указывайте владельца третьим параметром — иначе поиск пойдёт по всем элементам всех владельцев.
Для иерархических справочников второй параметр (поиск по полному коду) имеет смысл, когда у справочника включены серии кодов «В пределах подчинения» — тогда коды могут повторяться в разных ветках, и уточнение родителя становится обязательным для однозначного результата.
Поиск по наименованию и его ограничения
Метод НайтиПоНаименованию ищет элемент по точному совпадению наименования. Синтаксис аналогичен: первый параметр — строка наименования, далее признак точного соответствия, родитель и владелец.
Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка", Истина);
Главная опасность метода — наименования не обязаны быть уникальными. В справочнике контрагентов легко встречаются дубликаты, и метод вернёт первый попавшийся элемент, который вовсе не обязательно тот, что нужен. Поэтому поиск по наименованию допустим как вспомогательный, но для надёжной идентификации лучше использовать код, ИНН или GUID.
Ещё один подводный камень — невидимые различия строк: лишние пробелы, разный регистр, неразрывные пробелы из скопированного текста. Если поиск «не находит» заведомо существующий элемент, проверьте строку через СокрЛП и сравнение без учёта регистра через запрос.
Поиск по реквизиту и по уникальному идентификатору
НайтиПоРеквизиту
Метод НайтиПоРеквизиту ищет элемент по значению произвольного реквизита, указанного по имени. Классический пример — поиск контрагента по ИНН:
Найденный = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7701234567");
Если Не Найденный.Пустая() Тогда
// элемент найден, можно работать со ссылкой
КонецЕсли;
Ограничения: метод не работает с реквизитами неограниченной длины и реквизитами табличных частей. Если реквизит не проиндексирован, на больших справочниках поиск будет идти полным перебором — в этом случае проверьте настройку индексирования в конфигураторе или перейдите на запрос.
ПолучитьСсылку по GUID
Когда известен уникальный идентификатор элемента — например, он пришёл из внешней системы при обмене, — ссылку получают напрямую, без поиска по данным:
УИД = Новый УникальныйИдентификатор("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
ЭлементСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);
Если ЭлементСсылка.ПолучитьОбъект() = Неопределено Тогда
Сообщить("Элемента с таким GUID нет в базе");
КонецЕсли;
Важная особенность: ПолучитьСсылку не обращается к базе для проверки существования — она просто конструирует ссылку из идентификатора. Поэтому проверка существования выполняется отдельно: попыткой получить объект (как в примере) или запросом по ссылке. В типовых модулях для этого есть функция вида «СсылкаСуществует» в общих модулях работы со ссылками.
Получение элемента через запрос
Запрос — универсальный способ, когда условия поиска сложнее одного поля: несколько отборов, поиск без учёта регистра, выбор сразу нескольких элементов или получение полей элемента одним обращением. Запрос также предпочтителен в циклах: один запрос с пакетной выборкой заменяет сотни вызовов НайтиПоКоду.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН = &ИНН
| И НЕ Контрагенты.ПометкаУдаления";
Запрос.УстановитьПараметр("ИНН", "7701234567");
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
КонтрагентСсылка = Выборка.Ссылка;
КонецЕсли;
Обратите внимание на фильтр НЕ ПометкаУдаления. Встроенные методы поиска находят и помеченные на удаление элементы, что часто становится источником ошибок: обработка подставляет в документ элемент, который пользователь считает удалённым. В запросе такие элементы легко исключить условием.
Если в цикле обрабатывается много строк и для каждой ищется элемент справочника, соберите все искомые значения в таблицу значений, поместите её во временную таблицу запроса и соедините со справочником одним запросом. Это на порядок быстрее поиска в цикле.
Проверка результата и работа с найденным элементом
Любой поиск может ничего не найти, поэтому результат всегда проверяется. Для методов поиска проверка выполняется через Пустая() или сравнением с пустой ссылкой. Для ПолучитьСсылку — через получение объекта или запрос существования.
Если нужно не только найти, но и прочитать или изменить данные элемента, по ссылке получают объект:
Если Не ЭлементСсылка.Пустая() Тогда
ЭлементОбъект = ЭлементСсылка.ПолучитьОбъект();
ЭлементОбъект.Комментарий = "Обновлено обработкой";
ЭлементОбъект.Записать();
КонецЕсли;
Не вызывайте ПолучитьОбъект() без необходимости: каждый вызов читает все данные элемента из базы. Если нужно только значение одного реквизита, к нему можно обратиться прямо через ссылку (ЭлементСсылка.ИНН) — платформа сама выполнит точечное чтение, — а для массового чтения полей используйте запрос.
Как проверить результат
Пустая() возвращает Ложь
Пустая() возвращает Истина — элемент не найден
ПолучитьОбъект() вернул объект
ПолучитьОбъект() вернул Неопределено — элемента нет
ПометкаУдаления = Ложь
Элемент помечен на удаление — подставлять его в документы нельзя
Типичные ошибки при программном поиске элементов
Первая и самая частая ошибка — отсутствие проверки на пустую ссылку. Код продолжает выполняться, пустая ссылка записывается в реквизит документа, и ошибка всплывает гораздо позже, уже в данных учёта.
Вторая группа ошибок связана с типами и форматами: передача строки вместо числа в НайтиПоКоду, потеря лидирующих нулей строкового кода, поиск по наименованию без учёта пробелов. Третья — игнорирование контекста: поиск в подчинённом справочнике без указания владельца, поиск в иерархическом справочнике без учёта родителя, нахождение помеченных на удаление элементов.
Часто задаваемые вопросы
Чем ссылка отличается от объекта справочника?
Ссылка — это лёгкий указатель на элемент, достаточный для записи в реквизиты и сравнений. Объект — полная копия данных элемента в памяти, нужная для изменения и записи. Получение объекта всегда означает чтение из базы, поэтому без необходимости его не вызывают.
Как найти элемент, если известна только часть наименования?
Встроенные методы ищут только по точному совпадению. Для поиска по подстроке используйте запрос с оператором ПОДОБНО, например: ГДЕ Наименование ПОДОБНО "%Ромашка%". Учтите, что такой поиск не использует индекс эффективно и на больших справочниках работает медленно.
НайтиПоКоду не находит элемент, хотя он есть в базе. Почему?
Чаще всего несовпадение типа или формата: код строковый с лидирующими нулями, а передано число или строка без нулей. Также проверьте, не ищете ли вы в подчинённом справочнике без указания владельца и не помечен ли элемент на удаление с нестандартными настройками видимости.
Как проверить, что элемент по GUID реально существует?
Вызовите у ссылки ПолучитьОбъект(): если элемента нет, вернётся Неопределено. Альтернатива без загрузки объекта — запрос вида ВЫБРАТЬ Ссылка ИЗ Справочник.Имя ГДЕ Ссылка = &Ссылка и проверка, что результат не пустой.
Что быстрее: НайтиПоКоду или запрос?
Для одиночного поиска по индексированному полю разница незначительна — оба варианта выполняют одно обращение к индексу. Запрос выигрывает, когда нужно найти много элементов сразу или заодно получить их реквизиты: один запрос заменяет множество вызовов встроенных методов.
Как получить предопределённый элемент справочника?
Обращением через менеджер по имени предопределённого элемента: Справочники.Валюты.Рубль. Имя предопределённого элемента задаётся в конфигураторе и доступно в коде напрямую, без поиска.
Что важно запомнить
Для поиска по коду и наименованию используйте НайтиПоКоду и НайтиПоНаименованию, по реквизитам — НайтиПоРеквизиту, по GUID — ПолучитьСсылку, для сложных условий — запрос. Всегда проверяйте результат: Пустая() для методов поиска, ПолучитьОбъект() или запрос для ссылки по GUID. Исключайте помеченные на удаление элементы и не используйте ПолучитьОбъект() без необходимости.