К статье
Практический материал

Разработка и Конфигурация · 13 мин

Модуль менеджера в 1С: как обратиться к объекту

Как работает модуль менеджера в 1С и как обратиться к объекту: методы менеджеров, примеры кода, типичные ошибки и рекомендации для разработчика.

Модуль менеджера в 1С — это отдельный вид модуля, который существует у прикладных объектов конфигурации: справочников, документов, перечислений, планов видов характеристик, регистров и других. В нём размещают код, относящийся не к конкретному элементу или документу, а к типу объекта в целом: создание новых объектов, поиск, проверки уникальности, печатные формы, заполнение по умолчанию.

Главная сложность для начинающих разработчиков — понять, что из модуля менеджера нельзя обратиться к данным конкретного объекта напрямую, как из модуля объекта. В модуле менеджера нет переменной «ЭтотОбъект», нет доступа к реквизитам текущего экземпляра — потому что такого экземпляра просто не существует в момент выполнения. Чтобы работать с данными, нужно сначала получить объект через ссылку или создать новый.

Обращение к объекту из модуля менеджера строится по одной схеме: получить ссылку (из параметра, запроса или поиска), вызвать метод ПолучитьОбъект(), изменить данные и записать. Ниже разобраны все варианты с примерами кода, ограничениями и типичными ошибками.

Что такое модуль менеджера и чем он отличается от модуля объекта

У каждого прикладного объекта конфигурации есть несколько модулей: модуль объекта, модуль менеджера, модуль формы, модуль команды. Модуль объекта исполняется в контексте конкретного экземпляра — в нём доступны реквизиты, табличные части и переменная ЭтотОбъект. Модуль менеджера исполняется «в вакууме»: платформа вызывает его методы через менеджер типа, например Справочники.Номенклатура.НайтиПоКоду(), и никакого конкретного элемента в этот момент не существует.

Отсюда следуют практические правила. В модуле менеджера нельзя писать Наименование = "Тест" — платформа выдаст ошибку, потому что переменной с таким именем нет. Нельзя обратиться к табличной части. Зато можно вызывать методы самого менеджера: СоздатьЭлемент(), СоздатьДокумент(), НайтиПоНаименованию(), ПолучитьСсылку(), Выбрать().

Какие методы доступны через менеджер

Состав методов зависит от типа объекта. У справочников и планов видов характеристик есть СоздатьЭлемент() и СоздатьГруппу(), у документов — СоздатьДокумент(), у регистров сведений — СоздатьНаборЗаписей() и СоздатьМенеджерЗаписи(). Общие для большинства типов методы: НайтиПоКоду(), НайтиПоНаименованию(), НайтиПоРеквизиту(), ПолучитьСсылку(), Выбрать(), ПустаяСсылка().

Все эти методы доступны непосредственно внутри модуля менеджера без префикса — достаточно написать НайтиПоКоду(Код). Извне (из общего модуля, модуля формы, другого объекта) к ним обращаются через полное имя: Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка"). Экспортные процедуры и функции, которые вы добавляете в модуль менеджера, вызываются так же: Документы.РеализацияТоваров.ПроверитьЗаполнение(Ссылка).

ЗадачаМетод менеджераРезультат
Создать новый элемент справочникаСоздатьЭлемент()Объект (ещё не записан)
Создать новый документСоздатьДокумент()Объект (ещё не записан)
Найти существующий элементНайтиПоКоду(), НайтиПоНаименованию(), НайтиПоРеквизиту()Ссылка или пустая ссылка
Получить ссылку по УИДПолучитьСсылку(УникальныйИдентификатор)Ссылка
Обойти все элементыВыбрать()Выборка ссылок

Как обратиться к конкретному объекту из модуля менеджера

Базовая схема состоит из трёх шагов: получить ссылку, получить объект по ссылке, работать с данными и записать. Ссылка приходит в модуль менеджера обычно как параметр экспортной процедуры — например, из формы списка или из обработки. Если ссылки нет, её находят методами поиска или запросом.

Процедура УстановитьПризнакАрхивный(НоменклатураСсылка) Экспорт

Если НоменклатураСсылка.Пустая() Тогда

Возврат;

КонецЕсли;

ОбъектНоменклатуры = НоменклатураСсылка.ПолучитьОбъект();

ОбъектНоменклатуры.Архивный = Истина;

ОбъектНоменклатуры.Записать();

КонецПроцедуры

Обратите внимание: метод ПолучитьОбъект() выполняет чтение из базы данных. Если вам нужно только проверить значение реквизита без изменения, читать весь объект не обязательно — значения реквизитов доступны прямо через ссылку: НоменклатураСсылка.Архивный. Это работает быстрее, потому что платформа выбирает только нужные поля. Полный объект получайте только тогда, когда планируете его менять и записывать.

Порядок обращения к объекту
  1. 1
    Получите ссылку: параметр процедуры, поиск по коду или наименованию, запрос
  2. 2
    Проверьте, что ссылка не пустая: Ссылка.Пустая()
  3. 3
    Если нужно изменить данные — вызовите Ссылка.ПолучитьОбъект()
  4. 4
    Измените реквизиты или табличные части объекта
  5. 5
    Вызовите Объект.Записать() и проверьте отсутствие исключений

Создание нового объекта из модуля менеджера

Вторая частая задача — создать новый элемент или документ. Для этого используются методы СоздатьЭлемент() и СоздатьДокумент(). Они возвращают объект, который существует только в памяти: в базе он появится только после вызова Записать(). До записи у объекта нет ссылки — точнее, ссылка есть, но она ещё не связана с данными в базе, и получить её можно через ПолучитьСсылкуНового() после её установки.

Функция СоздатьКонтрагента(Наименование, ИНН) Экспорт

Существующий = НайтиПоРеквизиту("ИНН", ИНН);

Если Не Существующий.Пустая() Тогда

Возврат Существующий;

КонецЕсли;

НовыйКонтрагент = СоздатьЭлемент();

НовыйКонтрагент.Наименование = Наименование;

НовыйКонтрагент.ИНН = ИНН;

НовыйКонтрагент.Записать();

Возврат НовыйКонтрагент.Ссылка;

КонецФункции

Такая функция в модуле менеджера справочника «Контрагенты» — типовой приём: логика создания и проверки дублей инкапсулирована в одном месте, а вызывается откуда угодно через Справочники.Контрагенты.СоздатьКонтрагента(Наименование, ИНН). Это удобнее, чем размазывать код создания по общим модулям и формам.

Работа с регистрами сведений

У регистров сведений вместо элемента создаётся менеджер записи или набор записей. Для одной записи: Менеджер = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи(), заполнение измерений и ресурсов, затем Менеджер.Записать(). Для нескольких записей — набор записей с отбором. Внутри модуля менеджера регистра обращение идёт без префикса: СоздатьМенеджерЗаписи().

Контекст сервера и клиента: где выполняется модуль менеджера

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

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

Типичные ошибки при обращении к объекту

Самая частая ошибка — попытка обратиться к реквизиту объекта в модуле менеджера без получения объекта. Платформа сообщит «Переменная не определена» или «Поле объекта не обнаружено». Вторая по частоте — вызов ПолучитьОбъект() у пустой ссылки: результатом будет Неопределено, и следующая строка обращения к реквизиту упадёт с ошибкой. Всегда проверяйте ссылку на пустоту.

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

Типичные ошибки
01
Обращение к реквизиту напрямую в модуле менеджера — ошибка компиляции, экземпляра объекта нет
02
ПолучитьОбъект() у пустой ссылки — результат Неопределено и падение на следующей строке
03
Изменение объекта без вызова Записать() — данные не сохраняются
04
Чтение ПолучитьОбъект() ради одного реквизита — лишняя нагрузка, читайте через ссылку
05
Попытка открыть форму или показать диалог из модуля менеджера — модуль работает только на сервере

Как проверить, что код работает правильно

После написания процедуры в модуле менеджера проверьте её на тестовой копии базы. Создайте тестовый элемент, вызовите процедуру с его ссылкой и убедитесь, что данные изменились. Проверьте граничные случаи: пустая ссылка, ссылка на помеченный на удаление объект, ссылка на объект другого типа, если тип параметра не ограничен.

Полезно добавить защитные проверки в сам код: проверка Пустая(), проверка типа параметра через ТипЗнч(), оборачивание записи в попытку с выводом текста ошибки через ОписаниеОшибки(). Это особенно важно для методов, которые вызываются из обменов и фоновых заданий, где ошибку некому увидеть интерактивно.

Контрольные точки

Как проверить результат

Ссылка передана в процедуру
Норма

Ссылка.Пустая() возвращает Ложь

Тревожный признак

Ссылка пустая — ПолучитьОбъект() вернёт Неопределено

Объект изменён и записан
Норма

После Записать() реквизит в базе имеет новое значение

Тревожный признак

Значение старое — вероятно, пропущен вызов Записать()

Вызов из клиентского кода
Норма

Метод вызывается через серверную процедуру формы

Тревожный признак

Ошибка вызова — модуль менеджера недоступен на клиенте

Когда использовать модуль менеджера, а когда — общий модуль

Правило простое: если логика относится к одному конкретному типу объектов — размещайте её в модуле менеджера этого типа. Проверка дублей контрагента — в модуле менеджера справочника «Контрагенты». Расчёт итогов документа реализации — в модуле менеджера документа. Если логика работает с несколькими типами объектов или вообще не привязана к данным (строковые функции, работа с файлами) — ей место в общем модуле.

Преимущество модуля менеджера — вызовы читаются естественно: Документы.ЗаказКлиента.РассчитатьСкидку(ЗаказСсылка) понятнее, чем РаботаСДокументами.РассчитатьСкидкуЗаказа(ЗаказСсылка). Кроме того, при переносе объекта между конфигурациями его логика переезжает вместе с ним.

Модуль менеджера или общий модуль

Модуль менеджера

Логика одного типа объектов: создание, поиск, проверки, печать. Вызывается через ТипОбъекта.Метод()

Общий модуль

Логика, охватывающая несколько типов, или вспомогательные функции без привязки к данным

Модуль объекта

Поведение конкретного экземпляра: обработка проведения, заполнение, проверка заполнения реквизитов

Итог

Что важно запомнить

Модуль менеджера работает с типом объекта, а не с экземпляром. Чтобы обратиться к данным: получите ссылку, проверьте её на пустоту, вызовите ПолучитьОбъект(), измените данные и запишите. Для чтения одного реквизита объект получать не нужно — читайте через ссылку. Модуль менеджера выполняется только на сервере.

Частые вопросы

Можно ли из модуля менеджера обратиться к табличной части документа?

Да, но только после получения объекта: Ссылка.ПолучитьОбъект(), затем обращение к табличной части по имени, например Объект.Товары. Напрямую по ссылке табличная часть недоступна — через ссылку читаются только реквизиты шапки. Для чтения табличной части без получения объекта используйте запрос.

Чем ПолучитьОбъект() отличается от чтения реквизита через ссылку?

ПолучитьОбъект() загружает объект целиком в память со всеми табличными частями и позволяет его изменить и записать. Чтение через ссылку (Ссылка.Реквизит) выбирает только указанное поле и доступно только для чтения. Если изменять данные не нужно, чтение через ссылку быстрее и дешевле.

Почему вызов метода модуля менеджера из формы не работает?

Скорее всего, вызов идёт из клиентской процедуры. Модуль менеджера компилируется только на сервере, поэтому в тонком и веб-клиенте из контекста &НаКлиенте он недоступен. Создайте в форме процедуру с директивой &НаСервере, вызовите метод менеджера из неё, а из клиентского кода обращайтесь к этой серверной процедуре.

Как создать элемент справочника и сразу получить его ссылку?

Вызовите СоздатьЭлемент(), заполните реквизиты, выполните Записать() — после этого свойство Ссылка объекта будет содержать ссылку на записанный элемент. До записи ссылка объекта ещё не связана с данными в базе, поэтому использовать её до Записать() нельзя.

Что будет, если вызвать ПолучитьОбъект() у битой ссылки?

Результатом будет Неопределено, и дальнейшее обращение к реквизитам вызовет ошибку. Перед получением объекта проверяйте ссылку: сначала на пустоту через Пустая(), а для надёжности — существование объекта запросом или попыткой чтения любого реквизита с обработкой исключения.

Можно ли вызывать экспортные функции модуля менеджера из других конфигураций через COM?

Через COM-соединение доступны те же менеджеры объектов, что и внутри конфигурации: Справочники, Документы и их методы. Экспортные функции модуля менеджера вызываются аналогично — Соединение.Справочники.Номенклатура.ИмяФункции(). Учитывайте, что параметры и возвращаемые значения должны быть сериализуемыми типами, иначе вызов завершится ошибкой.