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