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

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

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

Анализ исходной проблемы

Рассмотрим ситуацию, представленную в коде автора. Попытка удалить старые записи и записать новые по списку идентификаторов (GUID) приводит к фатальной ошибке. Проанализируем ключевые строки кода:


МассивГУИДов = Объект.Товары.Выгрузить(,"ГУИД");
НаборСтатусНоменклатуры = РегистрыСведений.СтатусНоменклатуры.СоздатьНаборЗаписей();
НаборСтатусНоменклатуры.Отбор.ГУИД.Установить(МассивГУИДов);
НаборСтатусНоменклатуры.Записать();

В этом фрагменте скрыто сразу несколько критических ошибок, которые блокируют работу алгоритма:

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

Разбор механизма работы Набора Записей

Давайте выясним причину, по которой платформа накладывает такие строгие ограничения. НаборЗаписей — это не просто коллекция строк, это проекция (выборка) данных из таблицы базы данных, ограниченная конкретными значениями измерений. Когда мы вызываем метод Записать(Истина), система выполняет две операции в рамках одной транзакции:

  1. Удаляет из базы данных все существующие записи, которые подпадают под установленный в наборе отбор.
  2. Записывает в базу данных все строки, которые в данный момент находятся в коллекции набора.

Если бы система позволяла устанавливать отбор «В списке», операция Записать(Истина) приводила бы к непредсказуемым результатам: очистке огромных пластов данных при записи всего нескольких строк. Поэтому 1С требует четко определять границы «порции» данных, с которой мы работаем.

Способ решения №1: Обработка в цикле (Классический подход)

Если нам необходимо обновить записи по списку различных ГУИДов, мы должны обрабатывать каждый ГУИД в отдельном наборе записей. Рассмотрим, как это реализовать правильно:


// Получаем массив уникальных идентификаторов корректно
МассивГУИДов = Объект.Товары.ВыгрузитьКолонку("ГУИД");

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

Способ решения №2: Использование Менеджера Записи

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

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


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

Важные нюансы при работе с типом УникальныйИдентификатор

При работе с типом УникальныйИдентификатор в измерениях следует учитывать специфику платформы 1С:

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

Выполнение записи в цикле (как в «Способе №1») может быть медленным, если строк в таблице очень много (тысячи). В таких случаях рекомендуется:

  1. Обернуть весь цикл в одну общую транзакцию, используя НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Это значительно ускорит работу с СУБД.
  2. Если записи в регистре имеют дополнительные измерения (например, Организация), обязательно включайте их в отбор. Чем точнее отбор, тем быстрее СУБД находит и блокирует нужный диапазон данных.
  3. Избегайте использования случайных GUID (V4) в качестве единственного измерения на огромных объемах данных, так как это приводит к сильной фрагментации индексов в SQL-таблицах.

Таким образом, основная ошибка заключалась в попытке использовать НаборЗаписей как универсальный контейнер для разных групп данных. Помните: один набор — одно значение для каждого измерения в отборе.

← На главную