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

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

При разработке алгоритмов проведения документов в 1С:Предприятии 8.2 и 8.3 программисты часто сталкиваются с ситуацией, когда при отладке в коллекции движений поле НомерСтроки остается равным нулю. Попытка установить это значение вручную приводит к ошибке выполнения, а система при записи набора может выдавать невнятные сообщения о конфликте в строке №2. Разберем подробно, как устроены механизмы работы с номерами строк и почему возникают подобные проблемы.

Особенности системного поля НомерСтроки

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

  1. Автозаполнение: Платформа 1С самостоятельно проставляет порядковые номера записей только в момент физической записи набора в базу данных. Пока данные находятся в оперативной памяти (внутри процедуры ОбработкаПроведения), значения в этом поле всегда будут равны 0.
  2. Запрет на запись: Данное поле закрыто для редактирования. Оно не предназначено для программного изменения пользователем или разработчиком. Именно поэтому при попытке присвоить значение напрямую (например, Движение.НомерСтроки = 1) система выдает ошибку: «Поле не предназначено для записи».
  3. Назначение: В регистрах накопления и бухгалтерии номер строки может входить в уникальный ключ записи, но в подчиненных регистрах сведений уникальность определяется комбинацией Период + Регистратор + Измерения. Номер строки здесь служит лишь для фиксации порядка следования записей.

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

Анализ программного кода и поиск логических ошибок

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


Для Каждого ТекСтрокаСотрудники Из Сотрудники Цикл
    Движение = Движения.АИС_ПодписантыОрганизаций.Добавить;
    Движение.Период = Дата;
    Движение.Организация = Организация; // Убедитесь, что здесь нет опечаток
    Движение.Действительна = Истина;
    Движение.Сотрудник = ТекСтрокаСотрудники.Сотрудник;
    Движение.Приоритет = ТекСтрокаСотрудники.Приоритет;
    // Пытаться записывать НомерСтроки здесь нельзя!
КонецЦикла;

В данном коде, если в табличной части Сотрудники окажутся две строки с одинаковым сотрудником (при условии, что Сотрудник — единственное измерение), система не сможет записать такой набор. Поскольку НомерСтроки не является ключом уникальности в регистре сведений, платформа «споткнется» на попытке добавить вторую запись с идентичными измерениями.

Проблема использования виртуальных таблиц в транзакции

Выясним причину, по которой ошибки могут возникать при использовании запросов к виртуальным таблицам (например, СрезПоследних) внутри ОбработкиПроведения. Рассмотрим опасный сценарий:

  1. Документ перепроводится.
  2. В начале процедуры движения не очищаются.
  3. Запрос СрезПоследних считывает данные, включая те, что уже записаны этим же документом ранее.
  4. Программа пытается добавить эти же данные в коллекцию движений еще раз.
  5. Итог: дублирование записей и ошибка при записи набора.

Чтобы избежать этой ситуации, всегда используйте метод Очистить() перед началом формирования новых записей и взводите флаг записи:


Движения.АИС_ПодписантыОрганизаций.Записывать = Истина;
Движения.АИС_ПодписантыОрганизаций.Очистить();
// Далее следует текст запроса и цикл заполнения

Также важно в запросах к регистру сведений добавлять условие исключения текущего регистратора, чтобы не «читать самих себя»:


Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Регистратор <> &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);

Рекомендации по правильному формированию движений

Разберем по шагам, как гарантированно избежать ошибок с номерами строк и дублями:

Шаг 1. Проверьте структуру регистра. Убедитесь, что все поля, которые вы считаете уникальными, действительно являются измерениями, а не ресурсами или реквизитами. Если Сотрудник — это ресурс, то в регистре может быть только одна запись на одну организацию в одну секунду (для периодических регистров).

Шаг 2. Используйте таблицы значений для подготовки данных. Вместо прямого добавления строк в движения, можно сначала сформировать ТаблицуЗначений, свернуть ее по измерениям (метод Свернуть()) для исключения дублей, а затем загрузить в регистр:


ТЗ_Движений = Движения.АИС_ПодписантыОрганизаций.ВыгрузитьКолонки();
// Заполняем ТЗ данными в цикле...
ТЗ_Движений.Свернуть("Организация, Сотрудник", "Приоритет"); // Удаляем дубли по ключам
Движения.АИС_ПодписантыОрганизаций.Загрузить(ТЗ_Движений);

Шаг 3. Контролируйте флаг записи. Если вы используете стандартный механизм проведения, достаточно установить Движения.ИмяРегистра.Записывать = Истина;. Если же вы вызываете Движения.ИмяРегистра.Записать(); принудительно внутри кода, помните, что повторная запись в конце процедуры (автоматическая) может привести к ошибкам блокировок, если не соблюдена осторожность.

Шаг 4. Внимание при копировании. Если вы создали документ путем копирования существующего, обязательно проверьте свойства самого объекта метаданных. Иногда «наследство» в виде установленных флагов в свойствах «Движения» (например, режим «Записывать выбранные») может конфликтовать с вашим программным кодом.

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

← На главную