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

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

При работе с независимыми регистрами сведений в 1С программисты часто сталкиваются с неприятной особенностью: если в форме записи изменить значение одного из измерений и нажать «Записать», в базе данных появляется новая запись, а старая остается нетронутой. В итоге вместо редактирования мы получаем дублирование данных. Рассмотрим подробнее, почему это происходит и как правильно организовать интерактивное редактирование записи.

Почему происходит дублирование записей?

Для начала разберем внутренние механизмы платформы 1С. Каждая запись в регистре сведений однозначно идентифицируется набором значений её измерений. Этот набор называется Ключом записи. Когда мы открываем форму существующей записи, платформа считывает этот ключ и «привязывает» форму к конкретной строке в базе данных.

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

Ошибка 1: Использование ручного удаления в событиях записи

Часто разработчики пытаются решить проблему «в лоб»: сохранить старые значения измерений в дополнительные реквизиты формы, а затем в процедуре ПослеЗаписиНаСервере найти старую запись по этим значениям и удалить её. Выясним причину, почему это плохая идея:

  1. Это нарушает транзакционность. Новая запись уже создана, и если при удалении старой произойдет сбой, база останется в некорректном состоянии.
  2. Событие ПослеЗаписиНаСервере предназначено для действий, которые не влияют на саму запись. Попытка программно менять тот же самый регистр в момент записи его объекта может привести к конфликтам блокировок.
  3. Это избыточный код, который усложняет поддержку системы. Платформа 1С уже умеет делать это автоматически.

Ошибка 2: Неправильная работа с Менеджером записи

Разберем ситуацию, когда программист в серверном коде выполняет преобразование: ЗаписьРегистраСервер = РеквизитФормыВЗначение("Запись"). При таком вызове создается объект типа РегистрСведенийМенеджерЗаписи. Если после изменения полей вы выполняете ЗначениеВРеквизитФормы(ЗаписьРегистраСервер, "Запись"), вы можете «затереть» внутреннее состояние формы, в котором хранится информация о исходном ключе записи. Рассмотрим, как этого избежать.

Правильное решение: Прямое изменение реквизита «Запись»

Самый эффективный способ — минимально вмешиваться в работу стандартных механизмов формы. В управляемых формах основной реквизит имеет тип РегистрСведенийМенеджерЗаписи. Если мы меняем его поля напрямую, платформа при нажатии кнопки «Записать» сама понимает, что ключ изменился. Она выполнит удаление записи со старым ключом и создание с новым в одной транзакции.

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


&НаКлиенте
Процедура СотрудникПриИзменении(Элемент)
    // Вызываем серверную процедуру для получения данных сотрудника
    СотрудникПриИзмененииНаСервере();
КонецПроцедуры

&НаСервере
Процедура СотрудникПриИзмененииНаСервере()
    // Работаем напрямую с реквизитом "Запись"
    Если ЗначениеЗаполнено(Запись.Сотрудник) Тогда
        
        // Получаем данные из справочника или кадрового учета
        Запись.ФизическоеЛицо = Запись.Сотрудник.ФизическоеЛицо;
        Запись.ДатаРождения   = Запись.Сотрудник.ФизическоеЛицо.ДатаРождения;
        
        // Пример использования общего модуля для получения кадровых данных
        МассивСотрудников = Новый Массив;
        МассивСотрудников.Добавить(Запись.Сотрудник);
        
        ДанныеСотрудника = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников, "Должность", ТекущаяДата());
        
        Если ДанныеСотрудника.Количество() > 0 Тогда
            Запись.Должность = ДанныеСотрудника[0].Должность;
        КонецЕсли;
        
    Иначе
        // Очистка полей при пустом сотруднике
        Запись.ДатаРождения = '00010101';
        Запись.ФизическоеЛицо = Справочники.ФизическиеЛица.ПустаяСсылка();
        Запись.Должность = Справочники.ДолжностиОрганизаций.ПустаяСсылка();
    КонецЕсли;
КонецПроцедуры

Важный момент: Обратите внимание, что в коде выше мы не используем РеквизитФормыВЗначение. Мы обращаемся к Запись.Сотрудник и Запись.Должность напрямую. В этом случае платформа сохраняет контекст редактирования. При сохранении формы 1С увидит, что текущее значение измерения Сотрудник отличается от того, которое было при открытии формы, и корректно «переедет» со старой записи на новую.

Когда все же может потребоваться Набор Записей?

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

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

Однако, проанализировав практику, можно сказать, что в 99% случаев для обычных управляемых форм достаточно просто отказаться от лишних преобразований типа ЗначениеВРеквизитФормы и РеквизитФормыВЗначение в пользу прямого изменения полей реквизита Запись.

Рекомендации по реализации

Чтобы ваша форма работала стабильно и не плодила дубли, следуйте этим правилам:

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

← На главную