Как исправить ошибку «Набор записей, принадлежащий менеджеру записи должен содержать ровно 1 запись» в 1С

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

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

Выясняем причину: архитектурное ограничение менеджера записи

Для начала проанализируем, как работает объект РегистрСведенийМенеджерЗаписи. В системе 1С:Предприятие существует два основных способа работы с регистрами сведений: через Набор записей и через Менеджер записи.

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

Если разработчик в процедуре ПередЗаписью модуля регистра сведений пишет код, очищающий набор (например, вызывая ЭтотОбъект.Очистить()), то в момент окончательной проверки перед записью в таблицу БД платформа видит «пустоту» там, где по правилам объекта МенеджерЗаписи должна быть одна строка. Именно это и вызывает фатальную ошибку, которую невозможно обойти даже установкой свойства ОбменДанными.Загрузка = Истина.

Ситуация в обмене данными

Рассмотрим ситуацию, когда ошибка возникает при обмене данными. Система загружает объект, используя менеджер записи. Мы хотим поставить фильтр: если организация в записи нам не подходит, мы не хотим ее записывать. Попытка просто «опустошить» менеджер в ПередЗаписью приводит к краху обмена.

Решение №1: Использование параметра Отказ

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

Проанализируем пример кода в модуле набора записей или менеджера записи:


Процедура ПередЗаписью(Отказ, Замещение)
	
	// Если это загрузка данных, проверяем условия фильтрации
	Если ОбменДанными.Загрузка Тогда
		
		// Логика проверки: например, не пропускаем лишние организации
		Если ЭтоЛишняяОрганизация(ЭтотОбъект.Организация) Тогда
			// Вместо очистки набора устанавливаем Отказ
			Отказ = Истина;
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Важное примечание: При использовании Отказ = Истина в процессе обмена данными нужно быть осторожным. Если обмен реализован через стандартные планы обмена, отказ в записи одного объекта может привести к тому, что вся транзакция загрузки пакета будет отменена. Если вы используете этот метод, убедитесь, что вызывающий код (обработка загрузки) умеет обрабатывать отказ записи конкретного объекта без прерывания всего процесса.

Решение №2: Переход на использование Набора записей

Если ваша задача — программно управлять записями и вы хотите иметь возможность «записывать пустоту» (то есть удалять существующую запись или игнорировать создание новой), следует отказаться от МенеджерЗаписи в пользу НаборЗаписей.

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


// Вместо использования Менеджера записи:
// Мз = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
// ... заполнение ключа ...
// Мз.Записать();

// Используем Набор записей:
Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Организация.Установить(ВыбраннаяОрганизация);
Набор.Отбор.Период.Установить(ВыбранныйПериод);

// Если условие выполняется — добавляем запись, если нет — оставляем набор пустым
Если НужноЗаписыватьДанные Тогда
    НоваяСтрока = Набор.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Данные);
КонецЕсли;

// Запись пустого набора просто очистит данные по отбору в базе
Набор.Записать(); 

Решение №3: Обработка события ПриЗаписи (для продвинутых случаев)

Иногда возникают ситуации, когда нам нужно позволить платформе сделать запись (чтобы не вызывать ошибку менеджера), но сразу после этого удалить её, если она не соответствует критериям. Это «костыльный» метод, но в некоторых закрытых механизмах обмена он остается единственным выходом.

Рассмотрим реализацию через событие ПриЗаписи. Основная сложность здесь — не попасть в бесконечную рекурсию. Чтобы избежать повторного входа в обработчик, мы будем использовать ОбменДанными.Загрузка.


Процедура ПриЗаписи(Отказ)
    
    Если ОбменДанными.Загрузка Тогда
        Возврат; // Выходим, если запись инициирована нашим же кодом удаления
    КонецЕсли;

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

КонецПроцедуры

Рекомендации по проектированию обмена

Проанализировав проблему, можно прийти к выводу, что лучшее решение лежит не в области обхода ошибки платформы, а в правильной настройке правил обмена (КД 2.0 или КД 3.0).

  1. Фильтрация на стороне источника: Старайтесь не выгружать лишние организации или документы еще на этапе формирования файла обмена. Это сэкономит трафик и избавит от проблем в приемнике.
  2. Событие «Перед загрузкой» в правилах: В правилах конвертации объектов (ПКО) или правилах обработки данных (ПОД) можно прописать логику проверки. Если объект не должен быть загружен, установите Отказ = Истина непосредственно в коде правила. В этом случае платформа даже не дойдет до создания объекта МенеджерЗаписи, и системная ошибка не возникнет.
  3. Использование Наборов в коде обмена: Если вы пишете свой обработчик загрузки (например, через COM или Web-сервис), всегда отдавайте предпочтение НаборуЗаписей. Это более универсальный объект, который стабильно ведет себя при любом количестве строк (0, 1 или 1000).

Таким образом, мы выяснили, что ошибка «Набор записей должен содержать ровно 1 запись» — это не баг платформы, а жесткое требование к целостности объекта МенеджерЗаписи. Понимание этого ограничения позволяет выбирать более надежные методы разработки и избегать трудноуловимых ошибок при синхронизации данных.

← На главную