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