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

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

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

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

Анализ проблемы и механизма платформы

Рассмотрим типовой сценарий, в котором возникает данная ситуация. В модуле набора записей регистра сведений размещен следующий код:


Процедура ПередЗаписью(Отказ, Замещение)
    Замещение = Истина;
    Для Каждого стр Из ЭтотОбъект Цикл
        стр.Закрыто = ТекущаяДата();
    КонецЦикла;
КонецПроцедуры

При выполнении записи набора платформа прерывает операцию с ошибкой несоответствия отбору. Выясним причину такого поведения:

  1. Назначение поля: Поле Закрыто в структуре метаданных регистра объявлено как Измерение, а не как ресурс или реквизит.
  2. Контроль целостности набора: Измерения регистра сведений формируют уникальный первичный ключ записи. Когда набор записей считывается или инициализируется, для него устанавливается фильтр в свойстве Отбор (например, по конкретному измерению, регистратору или периоду).
  3. Строгое платформенное правило: Если в свойстве Отбор набора записей для некоторого измерения включено использование (Использование = Истина), значения этого измерения во всех строках набора обязаны строго совпадать со значением, заданным в отборе.
  4. Попытка изменения ключа: Изменение значения измерения непосредственно в строке набора приводит к тому, что новое значение поля перестает соответствовать значению, зафиксированному в Отбор.ИмяИзмерения.Значение. В момент записи платформа выполняет валидацию и выбрасывает исключение.

Кроме того, изменение значения измерения по своей сути означает удаление старой записи и создание совершенно новой записи в базе данных, так как меняется первичный ключ строки таблицы.

Способ 1. Пересмотр структуры метаданных регистра

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

Разберем действия по шагам:

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

Способ 2. Корректная модификация записи через МенеджерЗаписи

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

Посмотрим на пример правильной замены значения измерения:


МенеджерЗаписи = РегистрыСведений.ТекущиеСтатусы.СоздатьМенеджерЗаписи();

// Заполняем текущие значения измерений для поиска исходной записи
МенеджерЗаписи.Объект = СсылкаНаОбъект;
МенеджерЗаписи.Закрыто = СтараяДата;
МенеджерЗаписи.Прочитать();

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

Способ 3. Перезапись с использованием двух наборов записей

Если требуется обновить группу записей, объединенных общим отбором, правильнее использовать два последовательных набора записей: один для очистки старых данных, второй — для записи новых.

Разберем данный алгоритм:


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

// 2. Создаем новый набор с обновленным отбором и новыми данными
НоваяДата = ТекущаяДата();

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

НоваяСтрока = НаборСоздание.Добавить();
НоваяСтрока.Объект = СсылкаНаОбъект;
НоваяСтрока.Закрыто = НоваяДата;
НоваяСтрока.Комментарий = "Обновлено программно";

НаборСоздание.Записать(Истина);

Дополнительные замечания по синтаксису

Обратим внимание на частые синтаксические и логические ошибки при работе с модулем набора записей:

  1. Вызов функции даты: Функция получения системной даты во встроенном языке 1С требует обязательного указания круглых скобок: ТекущаяДата(). Обращение без скобок вызовет ошибку компиляции.
  2. Свойство Записывать: Конструкция ЭтотОбъект.Записывать = Истина; применяется только для наборов движений регистров в модулях проведения документов. Для независимых регистров сведений данное свойство не используется.
← На главную