Почему дублируются записи при записи набора записей регистра накопления с параметром Замещать=Истина?

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

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

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

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

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

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

Как работает параметр Замещать = Истина

Многие начинающие разработчики полагают, что Замещать = Истина — это своего рода гарантия чистоты данных, которая предотвращает любые дубли. Однако этот параметр работает по строго определенному алгоритму внутри транзакции записи:

Во-первых, система обращается к базе данных и удаляет все существующие записи, которые соответствуют установленному в наборе отбору (обычно по Регистратору).

Во-вторых, система берет те записи, которые в данный момент находятся в объекте "набор записей" в оперативной памяти, и записывает их в таблицу регистра.

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

Скрытая логика: Модуль набора записей

Одной из самых частых причин "магического" появления лишних строк является код, размещенный в модуле набора записей самого регистра. У регистра накопления есть предопределенные события, такие как ПередЗаписью и ПриЗаписи.

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


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

Внутри модуля набора записей:


Процедура ПередЗаписью(Отказ, Замещать)
    // Если здесь написан код, который тоже анализирует набор
    // и добавляет в него записи, то ваши записи продублируются!
    Для Каждого Запись Из ЭтотОбъект Цикл
        // Логика, которая добавляет сторно
    КонецЦикла;
КонецПроцедуры

Так как процедура ПередЗаписью выполняется до того, как данные попадут в таблицу БД, любые изменения в коллекции ЭтотОбъект (которая и является набором записей) будут сохранены. Если логика в модуле регистра совпала с логикой в вашем коде, вы получите идентичные дубли.

Подписки на события и бизнес-логика

Помимо модуля самого регистра, не стоит забывать о Подписках на события. В крупных конфигурациях (например, 1С:ERP, УТ 11 или КА) разработчики часто используют подписки на событие ПередЗаписью для регистров накопления. Это позволяет реализовывать механизмы отражения данных в других регистрах или выполнять автоматические корректировки.

Проанализируем, почему это важно: подписки выполняются прозрачно для разработчика. Вы можете даже не знать, что при записи набора записей РН.ЗапасыИПотребности срабатывает программный модуль какой-нибудь подсистемы, который решает "помочь" и дозаполнить движения. Если ваша задача — программно изменить движения, которые и так формируются системой автоматически, вы неизбежно столкнетесь с дублированием.

Решение проблемы с помощью ДополнительныхСвойств

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

Рассмотрим правильный алгоритм записи:

  1. Перед вызовом метода Записать() добавим в набор записей специальный флаг-признак.
  2. В модуле набора записей проверим наличие этого флага.

Пример кода в месте вызова:


Набор = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Ссылка);
Набор.Прочитать();

// Добавляем флаг, чтобы отключить автоматическую логику
Набор.ДополнительныеСвойства.Вставить("ОтключитьАвтоматическоеФормирование", Истина);

// Выполняем добавление записей...
// ...

Набор.Записать(Истина);

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


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

    // Стандартная логика формирования движений
    // ...
КонецПроцедуры

Как отладить ситуацию дублирования?

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

  1. Точка останова в модуле регистра: Поставьте точку останова в процедуре ПередЗаписью модуля набора записей того регистра, где возникают дубли.
  2. Проверка количества записей: Когда отладчик остановится на этой точке, посмотрите значение ЭтотОбъект.Количество(). Если записей уже больше, чем вы добавили в своем основном коде, значит, они добавились где-то до этого момента.
  3. Стек вызовов: Внимательно изучите окно "Стек вызовов". Это позволит увидеть всю цепочку процедур, приведшую к записи. Вы сможете обнаружить подписки на события или вызовы из других модулей, о которых не подозревали.
  4. Поиск по конфигурации: Выполните глобальный поиск по имени регистра. Ищите места, где создается набор записей или где этот регистр используется в качестве объекта подписки на события.

Особенности типовых решений (ERP, УТ, КА)

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

Выясним причину: это делается для того, чтобы при ручной корректировке движений (если она разрешена) система могла пересчитать зависимые показатели. Если вы пытаетесь "обмануть" систему, записывая набор вручную, она может воспринять это как сигнал к пересчету и добавить свои строки поверх ваших.

Важный совет: Всегда проверяйте, не заполнена ли в регистре колонка ВидДвижения (для регистров остатков). Иногда дублирование кажется таковым только на первый взгляд, а на самом деле это записи с разными типами (Приход/Расход), которые формируются системой для балансировки показателей.

Резюме

Подведем итоги. Дублирование при записи набора с параметром Замещать=Истина — это не баг платформы, а следствие работы событийной модели 1С. Основные правила, которые помогут избежать этой проблемы:

Следуя этим рекомендациям, вы сможете создавать надежные механизмы модификации данных, которые будут работать предсказуемо и без ошибок.

← На главную