Как изменить значение измерения в регистре сведений 1С и обойти ошибку отбора?

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

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

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

Выясним причину ошибки

Уникальность любой записи в регистре сведений определяется её ключевыми полями — комбинацией периода (для периодических регистров) и всех его измерений. Когда мы создаем объект НаборЗаписей и устанавливаем отбор по конкретному измерению с помощью метода Установить(), объект строго ограничивает состав набора.

Платформа 1С отслеживает целостность отбора: если измерение было явно добавлено в свойство Отбор набора записей, модифицировать значение этого измерения внутри самих строк набора запрещено. Чтобы изменить значение измерения, формирующего ключ записи, необходимо удалить запись со старым ключом и записать новую с обновленным значением измерения.

Решение 1. Перезапись данных через НаборЗаписей

Рассмотрим по шагам основной алгоритм решения задачи при помощи объектной модели НаборЗаписей:

  1. Устанавливаем отбор по текущим (старым) значениям и считываем существующий набор записей методом Прочитать().
  2. Создаем новый набор записей (или копируем записи), в котором указываем обновленные значения измерений и ресурсов.
  3. Очищаем старый набор записей и записываем его в базу данных (тем самым удаляя старые данные).
  4. Записываем новый набор записей.

Посмотрим на практический пример кода, решающего данную задачу:


// 1. Создаем набор записей со старым отбором
НаборЗаписей = РегистрыСведений.МОЭСК_КомментарииКДокументам.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ОтветПолучен.Установить(Ложь);
НаборЗаписей.Отбор.РуководителиПроинформированыОПросрочке.Установить(Ложь);
НаборЗаписей.Отбор.КлиентПроинформирован.Установить(Ложь);
НаборЗаписей.Прочитать();

// 2. Подготавливаем новый набор записей
НовыйНаборДляЗаписи = РегистрыСведений.МОЭСК_КомментарииКДокументам.СоздатьНаборЗаписей();

Для Каждого Запись Из НаборЗаписей Цикл
    НоваяЗапись = НовыйНаборДляЗаписи.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяЗапись, Запись);
    
    // Меняем значения измерений или ресурсов
    НоваяЗапись.РуководителиПроинформированыОПросрочке = Истина;
    НоваяЗапись.ОтветПолучен = Истина;
    НоваяЗапись.ТекстОтвета = "Это Победа";
КонецЦикла; 

// 3. Удаляем старые записи и сохраняем новый набор
Если НаборЗаписей.Количество() > 0 Тогда
    НаборЗаписей.Очистить();
    НаборЗаписей.Записать(); // Удаляем данные старого отбора
    
    НовыйНаборДляЗаписи.Записать(Ложь); // Записываем новые данные без замещения
КонецЕсли;

Решение 2. Использование Менеджера записи для независимых регистров

Разберем еще один удобный подход. Если регистр сведений является независимым (режим записи «Независимый»), точечное редактирование одной записи проще выполнять через объект МенеджерЗаписи. Этот объект имитирует поведение платформы при интерактивном редактировании записей в режиме пользователя.

Посмотрим, как выглядит порядок действий в данном случае:

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

Пример кода с использованием МенеджерЗаписи:


МенеджерЗаписи = РегистрыСведений.МОЭСК_КомментарииКДокументам.СоздатьМенеджерЗаписи();

// Задаем ключи старой записи
МенеджерЗаписи.Период = ДатаСтарая;
МенеджерЗаписи.Измерение1 = СтароеЗначение;

// Читаем и удаляем старую запись
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
    МенеджерЗаписи.Удалить();
КонецЕсли;

// Устанавливаем новые значения и записываем
МенеджерЗаписи.Измерение1 = НовоеЗначение;
МенеджерЗаписи.Ресурс1 = ЗначениеРесурса;
МенеджерЗаписи.Записать();

Важные рекомендации по работе с транзакциями

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


НачатьТранзакцию();
Попытка
    // Очистка старых данных и запись новых
    НаборЗаписей.Очистить();
    НаборЗаписей.Записать();
    
    НовыйНаборДляЗаписи.Записать(Ложь);
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

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

← На главную