Как правильно изменить значения в регистре сведений и избежать ошибки «Запись не верна!»

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

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

Почему возникает ошибка при записи набора

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

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

Решение 1: Изменение состава отбора

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

Посмотрим на исправленный код:


НаборНапоминания = РегистрыСведений.Напоминания.СоздатьНаборЗаписей();
// Устанавливаем отбор только по тем полям, которые НЕ будут меняться
НаборНапоминания.Отбор.Пользователь.Установить(ТекущийПользователь);

НаборНапоминания.Прочитать();

Для каждого стр Из НаборНапоминания Цикл
    // Проверяем условие уже внутри цикла, а не в отборе набора
    Если стр.Завершено = Истина Тогда
        стр.Завершено = Ложь;
    КонецЕсли;
КонецЦикла;

НаборНапоминания.Записать();

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

Решение 2: Использование Менеджера записи

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

Разберем по шагам работу с менеджером записи:

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

Пример кода для менеджера записи:


Менеджер = РегистрыСведений.Напоминания.СоздатьМенеджерЗаписи();
Менеджер.Пользователь = ТекущийПользователь;
Менеджер.ВремяСобытия = ВыбранноеВремя;
Менеджер.Прочитать();

Если Менеджер.Выбран() Тогда
    Менеджер.Завершено = Ложь;
    Менеджер.Записать();
КонецЕсли;

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

Решение 3: Массовое изменение через промежуточную таблицу

В ситуациях, когда регистр содержит огромный объем данных, чтение всех записей пользователя в набор (как в Решении 1) может привести к просадке производительности или блокировкам. Если записей много, а изменить нужно лишь часть, проанализируем метод с использованием ТаблицыЗначений.

Алгоритм действий будет следующим:

  1. Выполняем запрос к регистру, чтобы получить только те записи, которые требуют корректировки.
  2. Выгружаем результат запроса в таблицу значений.
  3. Для каждой строки таблицы значений создаем отдельный набор записей с полным отбором по измерениям (создавая «точечный» фильтр).
  4. Записываем пустой набор (чтобы удалить старую запись) или меняем данные в наборе и записываем его без фильтрации по изменяемому полю.

Однако чаще всего достаточно использовать метод Загрузить() для набора записей, предварительно подготовив таблицу со всеми необходимыми данными для конкретного разреза (например, для одного пользователя).

Использование Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация построена на базе современных типовых решений, мы рекомендуем использовать методы БСП. Это позволяет сократить объем кода и избежать типичных ошибок с блокировками. В частности, модуль ОбменДаннымиСервер предоставляет удобные инструменты.

Рассмотрим метод ОбновитьЗаписьВРегистрСведений. Он автоматически обрабатывает создание менеджера записи, заполнение полей из переданной структуры и запись в базу данных. Это делает код чище и понятнее для других разработчиков.

Важные рекомендации по производительности

При работе с независимыми регистрами сведений стоит помнить о следующих моментах:

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

← На главную