Справочники и Данные · 12 мин
Как в 1С программно получить данные из справочника
Как в 1С программно получить данные из справочника: НайтиПоКоду, НайтиПоНаименованию, запросы, выборка. Примеры кода, ошибки и проверка результата.
Получение данных из справочника — одна из базовых операций при разработке и доработке конфигураций 1С. Справочники хранят нормативно-справочную информацию: контрагентов, номенклатуру, сотрудников, склады, и практически любой алгоритм обработки данных рано или поздно обращается к ним программно.
Встроенный язык 1С предлагает несколько способов доступа к элементам справочника: поиск по коду или наименованию, получение ссылки по уникальному идентификатору, перебор через выборку и запросы на языке запросов. Каждый способ имеет свою область применения, стоимость по производительности и ограничения.
Ниже разобраны основные методы с примерами кода, правила выбора подходящего способа, типичные ошибки и способы проверить, что программа действительно нашла нужный элемент, а не вернула пустую ссылку.
Объектная модель: менеджер, ссылка и объект справочника
Работа со справочником в коде строится через три сущности. Менеджер справочника доступен как Справочники.ИмяСправочника и предоставляет методы поиска и создания элементов. Ссылка (СправочникСсылка) — это лёгкий указатель на элемент: через неё можно обращаться к реквизитам через точку, но при первом обращении к каждому реквизиту выполняется обращение к базе данных.
Объект (СправочникОбъект) получают методом ПолучитьОбъект() у ссылки. Объект загружает элемент целиком в память и нужен, когда требуется изменить данные и записать их. Если задача — только прочитать данные, получать объект не нужно: это лишняя нагрузка и риск блокировок.
Пример чтения реквизита через ссылку без получения объекта:
Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
Если Не Контрагент.Пустая() Тогда
ИНН = Контрагент.ИНН;
КонецЕсли;
Как найти элемент по коду и наименованию
Методы НайтиПоКоду() и НайтиПоНаименованию() вызываются у менеджера справочника и возвращают ссылку на найденный элемент либо пустую ссылку, если ничего не найдено. Это самый быстрый способ точечного поиска, потому что код и наименование — стандартные реквизиты, по которым обычно построены индексы.
// Поиск по коду
Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000000123");
// Поиск по наименованию с учётом родителя
Группа = Справочники.Номенклатура.НайтиПоНаименованию("Материалы", Истина);
Элемент = Справочники.Номенклатура.НайтиПоНаименованию("Краска белая", Ложь, Группа);
У НайтиПоНаименованию() второй параметр отвечает за точное соответствие: Истина — поиск по полному совпадению, Ложь — по началу наименования. Третьим параметром можно передать ссылку на родителя для поиска внутри конкретной группы, четвёртым — владельца, если справочник подчинённый.
Важно помнить: если элементов с одинаковым наименованием несколько, метод вернёт только первый найденный. Для справочников, где дубли наименований допустимы, поиск по наименованию ненадёжен — используйте код, уникальный идентификатор или запрос с дополнительными условиями.
Получение элемента по уникальному идентификатору
Если известен GUID элемента — например, он сохранён в другой системе, регистре сведений или передан через веб-сервис, — ссылку получают методом ПолучитьСсылку():
УИД = Новый УникальныйИдентификатор("b2c3d4e5-...");
СсылкаНаЭлемент = Справочники.Номенклатура.ПолучитьСсылку(УИД);
Если СсылкаНаЭлемент.ПолучитьОбъект() = Неопределено Тогда
// Элемента с таким GUID в базе нет
КонецЕсли;
Особенность этого метода: он всегда возвращает ссылку, даже если элемента с таким идентификатором не существует. Поэтому стандартная проверка Пустая() здесь не поможет — надёжный способ убедиться в существовании элемента — попытаться получить объект или выполнить запрос по ссылке. Обращение к реквизитам несуществующего элемента даст так называемое «битое ссылочное» значение.
Этот способ оптимален для интеграций: GUID не меняется при переносе данных между базами в рамках типовых механизмов обмена, поэтому связь по идентификатору устойчивее, чем по коду, который может быть перенумерован.
Выборка элементов: перебор справочника в цикле
Метод Выбрать() возвращает выборку — последовательность ссылок, которую можно перебирать в цикле. Выборку можно ограничить родителем, владельцем и отбором по реквизитам:
Отбор = Новый Структура("ПометкаУдаления", Ложь);
Выборка = Справочники.Контрагенты.Выбрать( , , Отбор);
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Наименование + " — " + Выборка.ИНН);
КонецЦикла;
Выборка подходит для обхода небольших и средних справочников, когда нужно последовательно обработать каждый элемент. Однако у неё есть существенный недостаток: при обращении к реквизитам каждого элемента выполняются отдельные обращения к базе, что на больших объёмах приводит к заметному падению производительности.
Если нужно получить данные по многим элементам сразу — например, список номенклатуры с ценами или остатками, — выборку следует заменить запросом. Запрос получает все данные одним обращением к СУБД.
Получение данных запросом
Язык запросов — основной инструмент массового чтения данных в 1С. Запрос позволяет отобрать элементы по любым реквизитам, соединить справочник с другими таблицами, получить итоги и упорядочить результат:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
| И Номенклатура.Артикул = &Артикул";
Запрос.УстановитьПараметр("Артикул", "АРТ-1001");
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка строки результата
КонецЦикла;
КонецЕсли;
Обязательно передавайте значения условий через параметры (&ИмяПараметра), а не конкатенацией строк. Это защищает от ошибок синтаксиса при специальных символах в значениях и позволяет СУБД повторно использовать план запроса.
Для получения одного значения удобен метод Выгрузить() с последующим чтением первой строки, либо выборка с единственной итерацией. Если запрос вернул несколько строк, а нужна одна, добавьте конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 и упорядочивание, чтобы результат был детерминированным.
Сравнение способов получения данных
Быстрый точечный поиск по стандартным реквизитам. Не подходит для отбора по произвольным реквизитам и при дублях наименований.
Простой перебор элементов с отбором. Медленна на больших объёмах из-за обращений к базе на каждый элемент.
Оптимален для массового чтения, отборов по любым реквизитам и соединений. Требует аккуратности с параметрами и текстом запроса.
Для интеграций и обменов. Требует отдельной проверки существования элемента.
Как проверить результат и избежать пустых ссылок
Самая частая ошибка при программной работе со справочниками — использование результата поиска без проверки. Если элемент не найден, методы поиска возвращают пустую ссылку, и дальнейшая логика молча работает с пустым значением или падает с ошибкой.
Проверка выполняется двумя эквивалентными способами:
Элемент = Справочники.Номенклатура.НайтиПоКоду("000123");
Если Элемент.Пустая() Тогда
ВызватьИсключение "Номенклатура с кодом 000123 не найдена";
КонецЕсли;
// Альтернатива:
Если Элемент = Справочники.Номенклатура.ПустаяСсылка() Тогда
// Элемент не найден
КонецЕсли;
Для запросов проверка выполняется методом Результат.Пустой() до начала обхода выборки. Для ссылок, полученных по GUID, — через попытку получить объект или запросом по ссылке.
Как проверить результат
Ссылка не пустая, реквизиты читаются корректно
Ссылка пустая — элемент не найден или неверные параметры поиска
Результат.Пустой() возвращает Ложь, выборка содержит строки
Пустой результат — проверьте параметры и условия отбора
ПолучитьОбъект() возвращает объект, реквизиты доступны
ПолучитьОбъект() возвращает Неопределено — элемента нет в базе
Производительность и безопасная работа с данными
При работе в циклах избегайте поиска элементов внутри тела цикла, если значение можно найти один раз заранее. Повторяющиеся вызовы НайтиПоНаименованию() на каждой итерации — типичная причина медленной работы обработок. Кешируйте найденные ссылки в соответствии: ключ — поисковое значение, значение — ссылка.
При чтении реквизитов через точку от ссылки помните: каждое обращение к новому реквизиту — это обращение к базе. Если нужно прочитать много реквизитов многих элементов, запрос будет на порядок эффективнее.
Отдельного внимания заслуживают помеченные на удаление элементы. Методы поиска и выборки по умолчанию возвращают и их. Если бизнес-логика этого не требует, добавляйте отбор ПометкаУдаления = Ложь, иначе в документы и отчёты могут попасть «мёртвые» элементы.
- 1Определите, что известно об элементе: код, наименование, GUID или значения реквизитов.
- 2Выберите метод: НайтиПоКоду или НайтиПоНаименованию для стандартных реквизитов, запрос — для произвольных условий.
- 3Выполните поиск и сразу проверьте результат на пустую ссылку или пустой результат запроса.
- 4Прочитайте нужные реквизиты через ссылку или из выборки запроса.
- 5Если данных нет — обработайте ситуацию явно: сообщение пользователю, запись в журнал или создание нового элемента по правилам конфигурации.
FAQ
Как получить все элементы справочника без отбора?
Вызовите метод Выбрать() без параметров: Справочники.Имя.Выбрать() вернёт выборку всех элементов, включая помеченные на удаление и группы (для иерархических справочников). Для больших справочников предпочтительнее запрос без условий — он быстрее и позволяет выбрать только нужные поля.
Чем отличается НайтиПоНаименованию с параметром Истина от Ложь?
Параметр Истина включает поиск по точному совпадению всей строки наименования. Ложь (значение по умолчанию) означает поиск по началу наименования: запрос «Краска» найдёт и «Краска белая», и «Краска синяя» — вернётся первый по порядку элемент.
Как найти элемент справочника по значению произвольного реквизита?
Стандартных методов поиска по произвольным реквизитам нет. Используйте запрос с условием по нужному реквизиту, либо выборку Выбрать() с отбором через структуру — но отбор в выборке работает только по индексированным реквизитам, иначе будет ошибка. Запрос лишён этого ограничения.
Почему НайтиПоКоду не находит элемент, хотя код точно есть?
Частые причины: код хранится как строка с лидирующими нулями, а в метод передано число или строка без нулей; элемент помечен на удаление и поиск выполняется с отбором; в справочнике несколько элементов с одинаковым кодом в разных группах (при отключённом контроле уникальности). Передавайте код в том же типе и формате, в каком он хранится.
Как получить данные подчинённого справочника?
Используйте метод Выбрать() с параметром владельца: Справочники.ЕдиницыИзмерения.Выбрать(, СсылкаНаНоменклатуру) вернёт элементы, подчинённые конкретной номенклатуре. В запросе условие задаётся через поле Владелец: ГДЕ Единицы.Владелец = &Владелец.
Можно ли читать данные справочника из внешней обработки без изменения конфигурации?
Да. Внешние обработки и отчёты имеют полный доступ к встроенному языку и могут использовать все описанные методы: поиск, выборки и запросы. Ограничения могут быть связаны только с правами пользователя, под которым выполняется обработка, и с безопасным режимом, если он включён администратором.
Что важно запомнить
Точечный поиск — НайтиПоКоду и НайтиПоНаименованию, массовое чтение — запрос, интеграции — ПолучитьСсылку по GUID. Всегда проверяйте результат на пустую ссылку, исключайте помеченные на удаление элементы, а массовые изменения сначала тестируйте на копии базы.