Как из модуля объекта внешней обработки программно обратиться к справочнику и его реквизитам

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с данными в 1С из модуля объекта внешней обработки имеет свои специфические особенности, связанные с серверным контекстом выполнения кода. Часто перед разработчиком встает задача: проанализировать данные в справочниках (например, найти все договоры с определенной валютой) и совершить с ними какие-либо действия. В этой статье мы подробно разберем, как правильно выстраивать "путь" к справочникам, как обращаться к их реквизитам и какие методики работы считаются наиболее эффективными с точки зрения производительности.

Понимание контекста выполнения

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

Метод 1: Использование запроса — самый эффективный путь

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

Проанализируем пример кода для решения этой задачи:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДоговорыКонтрагентов.Ссылка КАК Ссылка,
    |	ДоговорыКонтрагентов.ВалютаВзаиморасчетов КАК Валюта
    |ИЗ
    |	Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
    |ГДЕ
    |	ДоговорыКонтрагентов.ВалютаВзаиморасчетов = &ВалютаРубли
    |	И НЕ ДоговорыКонтрагентов.ПометкаУдаления";

// Устанавливаем параметр запроса. 
// Поиск по коду — распространенный, но требующий осторожности метод.
Запрос.УстановитьПараметр("ВалютаРубли", Справочники.Валюты.НайтиПоКоду("643"));

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

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

Важный нюанс: в процессе обсуждения на форуме выяснилось, что распространенной ошибкой является пропуск реквизита в тексте запроса. Если вы хотите использовать значение реквизита в логике Если...Тогда, его обязательно нужно включить в секцию ВЫБРАТЬ вашего запроса.

Метод 2: Использование функций общего назначения (оптимизация чтения)

Если ваша цель — просто прочитать значение реквизита "Валюта" у конкретной ссылки, не используя запрос для списка, крайне не рекомендуется использовать метод ПолучитьОбъект(). Этот метод считывает абсолютно все поля справочника, включая табличные части, что создает избыточную нагрузку на сервер и сеть.

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


// Вместо Ссылка.ПолучитьОбъект().ВалютаВзаиморасчетов
Валюта = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаДоговор, "ВалютаВзаиморасчетов");

Если Валюта = Справочники.Валюты.НайтиПоКоду("643") Тогда
    // Ваша логика
КонецЕсли;

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

Анализ рисков при поиске по коду

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

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

Работа с подчиненными справочниками

Выясним еще одну важную деталь: справочник ДоговорыКонтрагентов почти всегда является подчиненным справочнику Контрагенты. При поиске конкретного договора или обращении к нему из модуля внешней обработки, мы должны учитывать владельца. Если мы просто ищем "Договор №1", система может найти десятки таких договоров у разных контрагентов.

Рассмотрим, как правильно добавить фильтр по владельцу в запрос:


Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДоговорыКонтрагентов.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
    |ГДЕ
    |	ДоговорыКонтрагентов.Владелец = &Контрагент";
Запрос.УстановитьПараметр("Контрагент", ТекущийКонтрагентСсылка);

Проверка наличия реквизитов через метаданные

Иногда возникают ситуации (как в Сообщениях 2 и 13), когда разработчик не уверен в точном программном имени реквизита: ВалютаОплаты, ВалютаВзаиморасчетов или ВалютаДокумента. Чтобы код был универсальным и не вызывал ошибок при обращении к несуществующему полю, мы можем программно проверить метаданные.

Рассмотрим пример такой проверки:


ИмяРеквизита = "ВалютаВзаиморасчетов";
Если Метаданные.Справочники.ДоговорыКонтрагентов.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
    // Реквизит существует, можно безопасно использовать в запросах или обращении через точку
Иначе
    Сообщить("В данной версии конфигурации реквизит " + ИмяРеквизита + " не найден!");
КонецЕсли;

Массовое изменение данных и транзакции

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

Применим безопасную схему записи:


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

Резюме

Для того чтобы успешно получить "путь" к справочнику и его данным из модуля объекта внешней обработки, придерживайтесь следующих правил:

  1. Всегда используйте Запросы для поиска и фильтрации данных — это стандарт де-факто в разработке на платформе 1С.
  2. Если нужно просто получить значение одного поля, используйте ОбщегоНазначения.ЗначениеРеквизитаОбъекта.
  3. Избегайте метода ПолучитьОбъект() внутри циклов, если вам не требуется перезаписывать данные.
  4. Проверяйте имена реквизитов через Метаданные, если обработка должна работать в разных конфигурациях.
  5. Учитывайте подчиненность справочников (используйте поле Владелец в фильтрах).

Такой системный подход позволит вам писать надежный, быстрый и понятный код, который будет легко поддерживать в будущем.

← На главную