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