Часто в практике программирования на платформе 1С возникает задача: пользователь редактирует данные в таблице значений на форме (например, меняет сумму в одной из трех строк), и нам необходимо программно обновить соответствующую строку в независимом регистре сведений. Разберем по шагам, как правильно реализовать такое точечное обновление данных, какие объекты платформы лучше использовать и каких критических ошибок следует избегать.
Рассмотрим первоначальный подход, который часто применяют начинающие разработчики. Попытка обновить данные реализуется через объект НаборЗаписей. Посмотрим на пример кода, который вызывает проблемы:
&НаСервере
Процедура ИзменениеОбщейСуммыПриИзменении()
НаборЗаписей = РегистрыСведений.РеестрП.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Период.Установить(ТекущаяДата());
НаборЗаписей.Отбор.Организация.Установить(ОтборОрганизации);
НаборЗаписей.Прочитать();
Для каждого ЗаписьНабора из НаборЗаписей Цикл
ЗаписьНабора.СуммаДокумента = ВведенаяСумма;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
Проанализируем ситуацию и выясним причину, почему такой подход может быть опасен. Объект НаборЗаписей предназначен для работы с массивом данных. При записи набора метод Записать() по умолчанию использует параметр Замещать = Истина. Это означает, что платформа физически удаляет из базы данных все старые записи, которые попадают под установленный отбор, и записывает на их место новые (те, что остались в наборе).
Если в ваш отбор по организации и дате попало 10 записей, а вы хотите поменять только одну строку и записываете набор, не убедившись, что остальные 9 строк в нем сохранены корректно, есть огромный риск безвозвратно удалить нужные записи. Набор записей эффективен, когда нам нужно массово очистить, перезаписать или добавить большой блок данных (например, загрузить все данные по организации за день).
Для точечной работы с одной конкретной записью независимого регистра сведений рассмотрим использование объекта МенеджерЗаписи. Это самый безопасный способ обновить одну строку, не затрагивая остальные данные в базе.
Чтобы воспользоваться менеджером записи, нам необходимо строго указать значения всех измерений регистра (и период, если регистр периодический), после чего выполнить чтение, изменение и запись.
Разберем пример правильного кода с использованием менеджера записи:
&НаСервере
Процедура ИзменитьЗаписьРегистра(ИзмеренияСтроки, НоваяСумма)
// Создаем менеджер записи
МенеджерЗаписи = РегистрыСведений.РеестрП.СоздатьМенеджерЗаписи();
// Устанавливаем ключевые поля (Период и все Измерения)
МенеджерЗаписи.Период = ИзмеренияСтроки.Период;
МенеджерЗаписи.Организация = ИзмеренияСтроки.Организация;
// ... указываем остальные измерения, если они есть ...
// Читаем конкретную запись из базы
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
// Меняем нужный ресурс
МенеджерЗаписи.СуммаДокумента = НоваяСумма;
// Записываем изменения
МенеджерЗаписи.Записать();
Иначе
Сообщить("Запись не найдена в регистре!");
КонецЕсли;
КонецПроцедуры
Кода действительно становится немного больше, так как нужно перечислить все ключевые поля, но этот подход гарантирует сохранность соседних записей и правильную работу системы.
В первоначальном коде используется установка отбора: НаборЗаписей.Отбор.Период.Установить(ТекущаяДата());. Рассмотрим подробнее, почему за такой код можно "остаться после уроков".
ТекущаяДата() (а в клиент-серверной архитектуре более правильная ТекущаяДатаСеанса()) возвращает дату вместе со временем (с точностью до секунды).Для корректного отбора по периоду необходимо всегда очищать время. Правильно делать это так: НачалоДня(ТекущаяДатаСеанса()).
Часто возникает вопрос: можно ли использовать Уникальный Идентификатор (УИД) для поиска и обновления строки в регистре сведений, как это делается в справочниках или документах? Проанализируем архитектуру регистров в 1С.
В отличие от объектных данных (справочников, документов), записи регистров сведений не имеют объектной ссылки (поля Ссылка) и системного уникального идентификатора (UUID). Первичным ключом, который обеспечивает уникальность строки в независимом регистре сведений, является исключительно совокупность значений всех его измерений (и периода).
Двух записей с абсолютно одинаковыми измерениями в таком регистре существовать не может. Если бизнес-логика вашей задачи требует наличия искусственного УИД для каждой строки (например, для точной связи строки таблицы значений на форме со строкой в регистре), вам необходимо:
ИдентификаторСтроки).УникальныйИдентификатор или Строка (длиной 36 символов).Новый УникальныйИдентификатор() и записывать его в это измерение.Только после добавления такого физического измерения в структуру регистра базы данных, вы сможете делать по нему отбор. Простое добавление колонки-индикатора в таблицу значений на форме никак не свяжет данные с базой.
Подведем итог: для точечного изменения данных в регистрах сведений из таблиц значений всегда применяйте МенеджерЗаписи, аккуратно работайте с датами через НачалоДня() и помните, что уникальность записей регистра определяется его измерениями, а не скрытыми ссылками.