При работе с независимыми регистрами сведений в 1С программисты часто сталкиваются с неприятной особенностью: если в форме записи изменить значение одного из измерений и нажать «Записать», в базе данных появляется новая запись, а старая остается нетронутой. В итоге вместо редактирования мы получаем дублирование данных. Рассмотрим подробнее, почему это происходит и как правильно организовать интерактивное редактирование записи.
Для начала разберем внутренние механизмы платформы 1С. Каждая запись в регистре сведений однозначно идентифицируется набором значений её измерений. Этот набор называется Ключом записи. Когда мы открываем форму существующей записи, платформа считывает этот ключ и «привязывает» форму к конкретной строке в базе данных.
Проблема возникает в тот момент, когда мы меняем измерение (например, Сотрудника или Номенклатуру). С точки зрения платформы, изменение измерения — это изменение ключа. Если в процессе работы мы начинаем «перемудрять» с программным кодом, связь со старым ключом теряется. Система видит новый набор измерений и считает, что вы хотите создать абсолютно новую запись, не подозревая, что старую нужно удалить. Проанализируем типичные ошибки и найдем правильный путь решения.
Часто разработчики пытаются решить проблему «в лоб»: сохранить старые значения измерений в дополнительные реквизиты формы, а затем в процедуре ПослеЗаписиНаСервере найти старую запись по этим значениям и удалить её. Выясним причину, почему это плохая идея:
ПослеЗаписиНаСервере предназначено для действий, которые не влияют на саму запись. Попытка программно менять тот же самый регистр в момент записи его объекта может привести к конфликтам блокировок.Разберем ситуацию, когда программист в серверном коде выполняет преобразование: ЗаписьРегистраСервер = РеквизитФормыВЗначение("Запись"). При таком вызове создается объект типа РегистрСведенийМенеджерЗаписи. Если после изменения полей вы выполняете ЗначениеВРеквизитФормы(ЗаписьРегистраСервер, "Запись"), вы можете «затереть» внутреннее состояние формы, в котором хранится информация о исходном ключе записи. Рассмотрим, как этого избежать.
Самый эффективный способ — минимально вмешиваться в работу стандартных механизмов формы. В управляемых формах основной реквизит имеет тип РегистрСведенийМенеджерЗаписи. Если мы меняем его поля напрямую, платформа при нажатии кнопки «Записать» сама понимает, что ключ изменился. Она выполнит удаление записи со старым ключом и создание с новым в одной транзакции.
Посмотрим на пример кода, который должен располагаться в модуле формы записи. Допустим, нам нужно при изменении сотрудника перезаполнить его физическое лицо и должность, которые хранятся в ресурсах или других измерениях.
&НаКлиенте
Процедура СотрудникПриИзменении(Элемент)
// Вызываем серверную процедуру для получения данных сотрудника
СотрудникПриИзмененииНаСервере();
КонецПроцедуры
&НаСервере
Процедура СотрудникПриИзмененииНаСервере()
// Работаем напрямую с реквизитом "Запись"
Если ЗначениеЗаполнено(Запись.Сотрудник) Тогда
// Получаем данные из справочника или кадрового учета
Запись.ФизическоеЛицо = Запись.Сотрудник.ФизическоеЛицо;
Запись.ДатаРождения = Запись.Сотрудник.ФизическоеЛицо.ДатаРождения;
// Пример использования общего модуля для получения кадровых данных
МассивСотрудников = Новый Массив;
МассивСотрудников.Добавить(Запись.Сотрудник);
ДанныеСотрудника = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников, "Должность", ТекущаяДата());
Если ДанныеСотрудника.Количество() > 0 Тогда
Запись.Должность = ДанныеСотрудника[0].Должность;
КонецЕсли;
Иначе
// Очистка полей при пустом сотруднике
Запись.ДатаРождения = '00010101';
Запись.ФизическоеЛицо = Справочники.ФизическиеЛица.ПустаяСсылка();
Запись.Должность = Справочники.ДолжностиОрганизаций.ПустаяСсылка();
КонецЕсли;
КонецПроцедуры
Важный момент: Обратите внимание, что в коде выше мы не используем РеквизитФормыВЗначение. Мы обращаемся к Запись.Сотрудник и Запись.Должность напрямую. В этом случае платформа сохраняет контекст редактирования. При сохранении формы 1С увидит, что текущее значение измерения Сотрудник отличается от того, которое было при открытии формы, и корректно «переедет» со старой записи на новую.
В некоторых сложных случаях, если автоматика платформы по каким-то причинам не справляется (например, при сложной логике в подписках на события или при программном открытии формы с особыми параметрами), можно использовать механизм Набора записей. Рассмотрим этот алгоритм по шагам:
ПередЗаписьюНаСервере мы проверяем, изменились ли измерения.РегистрСведенийНаборЗаписей.Однако, проанализировав практику, можно сказать, что в 99% случаев для обычных управляемых форм достаточно просто отказаться от лишних преобразований типа ЗначениеВРеквизитФормы и РеквизитФормыВЗначение в пользу прямого изменения полей реквизита Запись.
Чтобы ваша форма работала стабильно и не плодила дубли, следуйте этим правилам:
ПослеЗаписи. Это «костыль», который рано или поздно приведет к потере данных или ошибкам блокировок.РегистрСведенийМенеджерЗаписи, и он назначен основным реквизитом формы (выделен жирным в списке реквизитов).Таким образом, секрет корректного редактирования измерений заключается в доверии стандартным механизмам управляемой формы 1С. Просто меняйте данные в реквизите Запись, и платформа сама позаботится о чистоте вашего регистра сведений.