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

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача: при оформлении документа (например, поступления оборудования) автоматически создать объект в справочнике и зафиксировать его состав в регистре сведений. На первый взгляд кажется логичным поместить этот код в процедуру ОбработкаПроведения, однако это решение таит в себе множество архитектурных ловушек. Рассмотрим подробнее, как реализовать эту задачу правильно, избегая дублирования данных и избыточных блокировок базы данных.

Анализ проблемы: почему нельзя создавать справочники при проведении?

Разберем ситуацию, описанную в теме. У нас есть документ «Поступление компьютеров» с табличной частью, где указаны комплектующие: системный блок, монитор, принтер и ИБП. Нам нужно создать элемент справочника Компьютеры и записать связку в регистр сведений СоставКомпьютера.

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

  1. Транзакционные блокировки: Проведение документа — это транзакция. Если внутри неё мы начинаем создавать и записывать новые объекты других типов (справочники), система накладывает дополнительные блокировки на таблицы. Это замедляет работу других пользователей.
  2. Проблема дублей: Документ могут перепроводить многократно. Если не реализовать сложную проверку на существование, база быстро заполнится одинаковыми элементами «Компьютер 1», «Компьютер 1 (копия)» и так далее.
  3. Целостность данных: Если проведение документа отменится из-за ошибки (например, не хватило прав или остатков), транзакция откатится. Однако логика работы со справочниками может быть настроена так, что «пустой» элемент в справочнике останется, создавая «мусор».

Выясним причину, по которой опытные разработчики рекомендуют переносить создание справочника в форму документа или в событие ПередЗаписью.

Решение №1: Создание элемента по кнопке в управляемой форме

Это наиболее прозрачный и безопасный способ для пользователя. Мы добавим в форму документа кнопку «Сформировать компьютер», которая выполнит всю работу на сервере и вернет готовую ссылку в реквизит документа.

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

Рассмотрим пример кода для реализации этой логики:


&НаКлиенте
Процедура КомандаСформироватьКомпьютер(Команда)
    // Передаем данные текущей строки на сервер
    ТекущиеДанные = Элементы.СоставОборудования.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Вызываем серверную функцию для поиска или создания
    СсылкаНаКомпьютер = СоздатьИлиНайтиКомпьютерНаСервере(ТекущиеДанные.НаименованиеКомпьютера);
    
    // Заполняем реквизит в документе
    ТекущиеДанные.КомпьютерСсылка = СсылкаНаКомпьютер;
КонецПроцедуры

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

Решение №2: Проектирование регистра сведений «Состав компьютера»

Чтобы эффективно хранить информацию о том, из каких частей состоит компьютер, проанализируем структуру регистра сведений. Оптимально использовать периодический регистр сведений. Это позволит не просто хранить текущий состав, но и видеть историю изменений (например, когда монитор был заменен на другой).

Рекомендуемая структура регистра:

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

Разберем пример кода в модуле объекта документа:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Очищаем старые записи по этому документу, если регистр подчинен регистратору
    Движения.СоставКомпьютера.Записывать = Истина;
    Движения.СоставКомпьютера.Очистить();
    
    Для Каждого ТекСтрока Из ТабличнаяЧасть Цикл
        
        // Проверяем, заполнен ли созданный ранее компьютер
        Если ТекСтрока.КомпьютерСсылка.Пустая() Тогда
            Сообщить("Не заполнен объект Компьютер в строке " + ТекСтрока.НомерСтроки);
            Отказ = Истина;
            Продолжить;
        КонецЕсли;
        
        // Создаем запись в регистре
        Движение = Движения.СоставКомпьютера.Добавить();
        Движение.Период = Дата;
        Движение.Компьютер = ТекСтрока.КомпьютерСсылка;
        Движение.СистемныйБлок = ТекСтрока.СистемныйБлок;
        Движение.Монитор = ТекСтрока.Монитор;
        Движение.Принтер = ТекСтрока.Принтер;
        Движение.ИБП = ТекСтрока.ИБП;
        
    КонецЦикла;
    
КонецПроцедуры

Как избежать «раздувания» справочника?

Если мы решили отказаться от справочника Компьютеры и хранить только текстовое название, мы можем использовать его как измерение регистра сведений с типом Строка. Однако это лишит нас возможности ссылаться на этот компьютер в других документах (например, в «Акте ремонта» или «Списании»).

Рассмотрим рекомендации по идентификации объектов:

Проанализируем ситуацию: использование функции НайтиПоНаименованию эффективно только в случае строгой дисциплины ввода данных. Если пользователь назовет компьютер один раз «Комп-1», а другой раз «Комп 1» (с пробелом), система создаст два разных элемента. Для автоматизированных систем лучше использовать скрытые технические реквизиты поиска.

Итоги и лучшие практики

Подводя итог, придерживайтесь следующего алгоритма действий при разработке подобных механизмов в 1С:

  1. Не создавайте справочники в ОбработкеПроведения. Это нарушает принципы работы с транзакциями.
  2. Используйте серверные функции для поиска и создания элементов, вызывая их из формы документа.
  3. Проверяйте существование объекта перед созданием НовыйОбъект.Записать(). Поиск по коду или уникальному идентификатору надежнее, чем по наименованию.
  4. Регистр сведений — лучшее место для хранения состава сложного оборудования. Делайте его периодическим, чтобы сохранить историю «жизни» компьютера.
  5. Разграничивайте контексты. Помните, что &НаКлиенте мы только взаимодействуем с пользователем, а &НаСервере — работаем с базой данных и объектами метаданных.

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

← На главную