Как правильно перезаписать значение в непериодическом независимом регистре сведений «Значения свойств объектов» в 1С?

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

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

Ошибка 1. Появление дубликатов при использовании Набора Записей

Рассмотрим стандартную попытку программной записи значения свойства с использованием объекта РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей(). Типичный ошибочный код выглядит следующим образом:


НаборЗаписей = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект); 
НаборЗаписей.Отбор.Свойство.Установить(НашеСвойство);
НаборЗаписей.Прочитать();

НоваяЗапись = НаборЗаписей.Добавить(); 
НоваяЗапись.Объект = СсылкаНаОбъект; 
НоваяЗапись.Свойство = НашеСвойство; 
НоваяЗапись.Значение = НовоеЗначение; 
НаборЗаписей.Записать(Истина);

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

Чтобы избежать этой ошибки при работе с набором записей, необходимо предварительно очищать прочитанный набор либо модифицировать существующие строки:


НаборЗаписей.Прочитать();
НаборЗаписей.Очистить(); // Удаляем прочитанные строки из набора в памяти перед добавлением новой
НоваяЗапись = НаборЗаписей.Добавить();
// Заполнение полей и запись

Ошибка 2. Использование Менеджера Записи и проблемы кэширования

Для работы с отдельными записями независимого регистра удобнее применять МенеджерЗаписи. Он не требует настройки отборов и вызова метода чтения набора:


МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНаОбъект; 
МенеджерЗаписи.Свойство = НашеСвойство; 
МенеджерЗаписи.Значение = НовоеЗначение; 
МенеджерЗаписи.Записать(Истина);

Однако если этот код выполняется в событии формы ПередЗаписью, разработчики часто замечают, что данные в регистре все равно остаются старыми или перезаписываются обратно. Это происходит из-за того, что на форме элемента справочника работает встроенная подсистема хранения дополнительных реквизитов и свойств (например, объект ОбработкаОбъектЗначенияСвойств).

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

Правильное решение: модификация данных через контекст формы

Если задача заключается в автоматическом изменении свойства прямо из формы элемента справочника перед сохранением, необходимо менять значение не напрямую в регистре сведений, а в табличной части обработки управления свойствами, связанной с формой.

Разберем рабочий алгоритм решения:

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

Посмотрим на пример итогового кода процедур в форме элемента:


Процедура ПередЗаписью(Отказ)
    УстановитьСвойствоУНоменклатуры("Вид номенклатуры", НоменклатурнаяГруппа.Наименование);
КонецПроцедуры

Процедура УстановитьСвойствоУНоменклатуры(НаименованиеСвойства, ЗначениеСвойства)
    // Находим нужный элемент плана видов характеристик
    НашеСвойство = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию(НаименованиеСвойства);
    Если НЕ ЗначениеЗаполнено(НашеСвойство) Тогда
        Возврат;
    КонецЕсли;

    // Находим строку в табличной части обработки свойств на форме
    НайденнаяСтрока = ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения.Найти(НашеСвойство, "Свойство");
    
    Если НайденнаяСтрока <> Неопределено Тогда
        // Заполняем значение свойства ссылкой на элемент справочника значений свойств
        НайденнаяСтрока.Значение = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию(ЗначениеСвойства); 
    КонецЕсли;    
КонецПроцедуры

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

← На главную