Как зарегистрировать независимый регистр сведений к обмену без ошибок в 1С?

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

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

«Ошибка при вызове метода контекста (ЗарегистрироватьИзменения). Недопустимое значение параметра (параметр номер '2')»

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

В чем первопричина ошибки? Разбираем поведение платформы

Метод ПланыОбмена.ЗарегистрироватьИзменения() принимает в качестве второго параметра объект, изменения которого нужно зафиксировать для узла обмена. Для регистров сведений таким объектом обычно выступает РегистрСведенийНаборЗаписей.

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

Давайте разберем это правило по деталям:

  1. Обязательность всех ключевых измерений: Если у измерения в конфигураторе включено свойство «Основной отбор», его значение обязательно должно быть задано в свойстве Отбор вашего набора записей. Пропустите хотя бы одно такое измерение — и платформа мгновенно выдаст ошибку во втором параметре.
  2. Запрет на лишние поля: Если у измерения отключен флаг «Основной отбор», или вы попытаетесь установить отбор по реквизиту или ресурсу регистра, платформа также откажется регистрировать изменения.
  3. Только прямое равенство: Вид сравнения в элементах отбора должен быть исключительно Равно. Использование списков значений, диапазонов дат или других видов сравнения недопустимо.

Разбор практического кейса

Рассмотрим ситуацию, с которой столкнулся разработчик в типовой конфигурации «Управление производственным предприятием» (УПП) при работе с регистром сведений Штрихкоды. Был написан следующий код в подписке на событие:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |	Штрихкоды.Штрихкод,
    |	Штрихкоды.Владелец,
    |	Штрихкоды.ХарактеристикаНоменклатуры,
    |	Штрихкоды.ТипШтрихкода,
    |	Штрихкоды.ЕдиницаИзмерения,
    |	Штрихкоды.СерияНоменклатуры,
    |	Штрихкоды.Качество
    |ИЗ
    |	РегистрСведений.Штрихкоды КАК Штрихкоды
    |ГДЕ
    |	Штрихкоды.Владелец = &Владелец
    |	И Штрихкоды.Штрихкод = &Штрихкод";

Запрос.УстановитьПараметр("Владелец", Источник.Отбор.Владелец.Value);
Запрос.УстановитьПараметр("Штрихкод", Источник.Отбор.Штрихкод.Value);

Выборка = Запрос.Выполнить().Выбрать();
Набор = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();

Пока Выборка.Следующий() Цикл
    Узел = ПланыОбмена.МойПланОбмена.НайтиПоНаименованию("МойПланОбмена");
    
    Набор.Отбор.Владелец.Установить(Выборка.Владелец);
    Набор.Отбор.ХарактеристикаНоменклатуры.Установить(Выборка.ХарактеристикаНоменклатуры);
    Набор.Отбор.Штрихкод.Установить(Выборка.Штрихкод);
    Набор.Отбор.ТипШтрихкода.Установить(Выборка.ТипШтрихкода);
    Набор.Отбор.ЕдиницаИзмерения.Установить(Выборка.ЕдиницаИзмерения);
    Набор.Отбор.Качество.Установить(Выборка.Качество);
    
    ПланыОбмена.ЗарегистрироватьИзменения(Узел, Набор);
КонецЦикла;

Несмотря на то, что программист заполнил почти все измерения в отборе, система выдавала ошибку. Проблема крылась в метаданных конфигурации: у регистра сведений Штрихкоды измерение СерияНоменклатуры также имеет признак «Основной отбор». Так как это измерение было упущено при заполнении отбора набора записей, метод ЗарегистрироватьИзменения() аварийно завершал работу.

Как только в код была добавлена строка установки отбора по сериям, ошибка полностью исчезла:

Набор.Отбор.СерияНоменклатуры.Установить(Выборка.СерияНоменклатуры);

Как правильно устанавливать отбор: Значение или Установить()?

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

Вариант 1. Прямое присвоение свойств (не рекомендуется):


Набор.Отбор.Владелец.Значение = Выборка.Владелец;
Набор.Отбор.Владелец.Использование = Истина;

Этот способ избыточен. Вам приходится вручную писать две строки кода для каждого измерения и следить за флагом активности отбора.

Вариант 2. Использование метода Установить() (рекомендуемый стандарт):

Набор.Отбор.Владелец.Установить(Выборка.Владелец);

Метод Установить() является стандартным инструментом платформы. Он лаконичен и автоматически выполняет три действия под капотом:

Использование этого метода делает код чище и снижает вероятность допустить опечатку.

Разбор типичных ошибок и «вредных советов» с форумов

При изучении подобных проблем на форумах можно встретить рекомендацию вызвать метод Набор.Прочитать() перед регистрацией изменений. Делать этого категорически не стоит!

Давайте разберемся, почему это плохой совет:

Критическая проблема производительности: регистрация в цикле

Посмотрим еще раз на исходный код решения. В нем кроется серьезная архитектурная уязвимость:


Пока Выборка.Следующий() Цикл
    // ... установка отборов ...
    ПланыОбмена.ЗарегистрироватьИзменения(Узел, Набор);
КонецЦикла;

Каждый вызов метода ЗарегистрироватьИзменения() внутри цикла порождает отдельный транзакционный запрос к таблице регистрации изменений (таблице изменений регистра сведений). Если у одного товара будет несколько десятков штрихкодов, или если происходит групповое перепроведение документов, система выполнит сотни мелких запросов к базе данных.

Это приводит к падению производительности и высокому риску возникновения взаимных блокировок (Deadlocks).

Как оптимизировать этот процесс?

Вместо вызова регистрации в цикле, если это возможно, старайтесь собирать данные и минимизировать количество вызовов. В современных версиях платформы (начиная с 8.3.21/8.3.25) методы регистрации изменений оптимизированы и могут работать с массивами объектов, что значительно сокращает количество обращений к СУБД.

Альтернативный и элегантный способ: Ключ записи регистра

Существует более изящный способ зарегистрировать изменение конкретной записи в независимом регистре сведений без ручного создания набора записей и перечисления всех его измерений. Это использование объекта РегистрСведенийКлючЗаписи.

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


// Создаем структуру параметров для ключа записи
ПараметрыКлюча = Новый Структура;
ПараметрыКлюча.Вставить("Владелец", Выборка.Владелец);
ПараметрыКлюча.Вставить("ХарактеристикаНоменклатуры", Выборка.ХарактеристикаНоменклатуры);
ПараметрыКлюча.Вставить("Штрихкод", Выборка.Штрихкод);
ПараметрыКлюча.Вставить("ТипШтрихкода", Выборка.ТипШтрихкода);
ПараметрыКлюча.Вставить("ЕдиницаИзмерения", Выборка.ЕдиницаИзмерения);
ПараметрыКлюча.Вставить("СерияНоменклатуры", Выборка.СерияНоменклатуры);
ПараметрыКлюча.Вставить("Качество", Выборка.Качество);

// Создаем сам ключ записи
КлючЗаписи = РегистрыСведений.Штрихкоды.СоздатьКлючЗаписи(ПараметрыКлюча);

// Регистрируем изменения по ключу записи
ПланыОбмена.ЗарегистрироватьИзменения(Узел, КлючЗаписи);

Этот способ позволяет платформе самостоятельно определить состав ключевых полей и зарегистрировать изменение без явного конструирования объекта набора записей.

Чек-лист для успешной регистрации изменений регистра сведений

Чтобы раз и навсегда застраховаться от ошибок при ручной регистрации записей регистра сведений к обмену, сверяйтесь со следующим чек-листом:

  1. Откройте конфигуратор и найдите ваш регистр сведений. Сверьте список его измерений.
  2. Для каждого измерения проверьте свойство «Основной отбор».
  3. В коде создания набора записей установите отбор (через метод Установить()) по всем измерениям, у которых этот флаг равен Истина.
  4. Убедитесь, что вы не пытаетесь установить отборы по ресурсам, реквизитам или тем измерениям, у которых «Основной отбор» выключен.
  5. Убедитесь, что сам регистр сведений включен в состав используемого плана обмена.
  6. Для периодических регистров сведений проверьте флаг «Основной отбор по периоду» — если он включен, поле Период также должно быть заполнено в отборе.
← На главную