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

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

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

В этой статье мы подробно разберем, как правильно организовать обращение к ресурсу регистра сведений из модуля управляемой формы документа, соблюдая стандарты разработки 1С и правила клиент-серверного взаимодействия.

Понимание клиент-серверной архитектуры

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

Попытка вызвать менеджер регистра напрямую на клиенте, например, написав код РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее() в процедуре с директивой &НаКлиенте, неизбежно приведет к синтаксической ошибке компиляции. Клиент просто «не знает» о существовании глобального контекста РегистрыСведений.

Для решения этой задачи нам в любом случае потребуется разделить логику:

  1. На клиенте мы фиксируем действие пользователя (например, изменение номенклатуры в строке).
  2. Передаем управление на сервер для извлечения данных из базы.
  3. Возвращаем полученное значение обратно на клиент и заполняем реквизиты формы.

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

Способ 1. Использование запроса (Рекомендуемый подход)

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

Для этого мы обратимся к виртуальной таблице СрезПоследних. Выполнять этот запрос мы будем в серверной функции с директивой компиляции &НаСервереБезКонтекста. Использование бесконтекстного вызова крайне важно: это исключает передачу всей формы (данных объекта, элементов управления) с клиента на сервер и обратно, что значительно ускоряет работу программы.

Разберем пример реализации такой функции:


&НаСервереБезКонтекста
Функция ПолучитьЦенуНоменклатурыЗапросом(Знач НоменклатураСсылка, Знач ДатаЦен)
    
    // Инициализируем новый запрос
    Запрос = Новый Запрос;
    
    // Формируем текст запроса к виртуальной таблице СрезПоследних
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
        |ИЗ
        |	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура = &Номенклатура) КАК ЦеныНоменклатурыСрезПоследних";
    
    // Устанавливаем параметры запроса для исключения SQL-инъекций и повышения производительности
    Запрос.УстановитьПараметр("Период", ДатаЦен);
    Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
    
    // Выполняем запрос и выгружаем результат
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Если запись найдена, возвращаем цену, иначе возвращаем 0
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Цена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

В данном примере мы наложили фильтр прямо в параметрах виртуальной таблицы: Номенклатура = &Номенклатура. Это позволяет СУБД выбрать только одну нужную запись, минимизируя нагрузку на сервер базы данных.

Способ 2. Использование методов менеджера регистра (Без запроса)

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

Посмотрим на пример работы с периодическим регистром сведений:


&НаСервереБезКонтекста
Функция ПолучитьЦенуНоменклатурыМетодом(Знач НоменклатураСсылка, Знач ДатаЦен)
    
    // Создаем структуру отбора. Ключами должны быть имена измерений регистра!
    Отбор = Новый Структура;
    Отбор.Вставить("Номенклатура", НоменклатураСсылка);
    
    // Метод возвращает структуру, содержащую значения всех ресурсов регистра
    СтруктураРесурсов = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ДатаЦен, Отбор);
    
    // Проверяем наличие свойства в структуре и возвращаем его значение
    Если СтруктураРесурсов.Свойство("Цена") Тогда
        Возврат СтруктураРесурсов.Цена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Важное предупреждение: При использовании методов Получить() и ПолучитьПоследнее() вы обязаны передавать в структуру отбора значения для всех измерений регистра. Если у регистра несколько измерений (например, Номенклатура, Характеристика, ТипЦен), а вы укажете в отборе только номенклатуру, система либо вернет пустые данные, либо отработает некорректно. Именно поэтому для многомерных регистров безопаснее и надежнее использовать первый способ (Запрос).

Для непериодического регистра сведений структура вызова будет аналогичной, но мы используем метод Получить() и нам не потребуется указывать дату:


&НаСервереБезКонтекста
Функция ПолучитьЗначениеНепериодическогоРегистра(Знач ОбъектАналитики)
    
    Отбор = Новый Структура("Аналитика", ОбъектАналитики);
    СтруктураРесурсов = РегистрыСведений.ИмяРегистра.Получить(Отбор);
    
    Если СтруктураРесурсов.Свойство("Ресурс") Тогда
        Возврат СтруктураРесурсов.Ресурс;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Интеграция решения в форму документа

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

Для этого мы создаем клиентский обработчик события ПриИзменении для поля ввода номенклатуры в табличной части.


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    
    // 1. Получаем данные текущей строки табличной части
    СтрокаТЧ = Элементы.Товары.ТекущиеДанные;
    
    // Проверяем, что строка действительно выбрана
    Если СтрокаТЧ = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // 2. Подготавливаем параметры для передачи на сервер
    ВыбранныйТовар = СтрокаТЧ.Номенклатура;
    
    // Если товар очистили - обнуляем цену и сумму, выходить дальше нет смысла
    Если Не ЗначениеЗаполнено(ВыбранныйТовар) Тогда
        СтрокаТЧ.Цена = 0;
        СтрокаТЧ.Сумма = 0;
        Возврат;
    КонецЕсли;
    
    // В качестве даты среза цен берем дату документа. 
    // Если документ новый и дата не заполнена - используем текущую дату сеанса.
    ДатаСреза = ?(ЗначениеЗаполнено(Объект.Date), Объект.Date, ТекущаяДатаСеанса());
    
    // 3. Вызываем нашу серверную функцию без контекста
    АктуальнаяЦена = ПолучитьЦенуНоменклатурыЗапросом(ВыбранныйТовар, ДатаСреза);
    
    // 4. Записываем полученную цену в строку табличной части
    СтрокаТЧ.Price = АктуальнаяЦена;
    
    // 5. Пересчитываем сумму строки
    СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Price;
    
КонецПроцедуры

Проанализируем преимущества данной схемы работы:

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

← На главную