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