Как работает автоматическое удаление движений при перепроведении документов в 1С:Предприятие 8

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

В процессе разработки на платформе «1С:Предприятие 8» одним из наиболее важных и при этом часто понимаемых поверхностно вопросов является механизм работы с движениями документов. Часто возникает вопрос: что происходит на уровне базы данных, когда мы перепроводим документ, в котором изменилось количество строк в табличной части? Удалятся ли старые записи полностью или система попытается обновить их выборочно? Разберем эту тему подробно, опираясь на логику работы платформы и механизмы СУБД.

Разбираемся в свойстве «Удаление движений»

Для начала проанализируем настройки самого документа в конфигураторе. Свойство Удаление движений может принимать несколько значений, и именно от них зависит поведение системы в момент нажатия кнопки «Провести».

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

Что происходит при уменьшении количества строк в документе?

Рассмотрим ситуацию, которую описывает автор вопроса: в старом документе было 10 движений, мы удалили 5 строк из табличной части и нажали «Провести». Каким образом «перезапишется» только часть движений?

Выясним причину: на самом деле термин «перезапись» в контексте 1С не означает частичное обновление строк (SQL UPDATE). Платформа работает с наборами записей. Набор записей по конкретному регистратору — это всегда целостная сущность. Когда выполняется метод НаборЗаписей.Записать(Истина), платформа подает СУБД команду на полное удаление всех существующих строк по данному регистратору в таблице регистра и последующую вставку новых строк.

Таким образом, даже если новых строк стало меньше (или они вовсе отсутствуют), старые данные будут полностью стерты. В базе данных не останется «лишних» записей от предыдущего проведения, так как операция удаления по фильтру Регистратор всегда предшествует операции вставки.

Физический уровень СУБД и транзакции

Посмотрим на ситуацию глазами SQL-сервера. Когда мы выполняем проведение документа в режиме замещения движений, внутри одной транзакции происходят следующие действия:

  1. Выполняется SQL-запрос вида DELETE FROM [ТаблицаРегистра] WHERE [Recorder] = 'УникальныйИдентификаторДокумента'.
  2. Если в новом наборе записей есть строки, выполняется серия запросов INSERT INTO для каждой новой строки.
  3. Транзакция фиксируется (Commit).

Это объясняет, почему количество записей может быть любым. Если программист передал пустой набор записей и вызвал Записать(), то выполнится только DELETE, и движения просто исчезнут, что и требуется при логическом удалении данных.

Проблема «Задвоения» и расчет остатков

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

Представим сценарий: на складе 10 единиц товара. Документ «Расходная накладная» уже проведен и списал 5 единиц. В регистре числится остаток 5. Мы решили перепровести этот документ, изменив количество с 5 на 7. Если мы используем режим Удалять автоматически при отмене проведения, то внутри процедуры ОбработкаПроведения запрос к остаткам вернет нам 5 единиц (так как старые движения документа еще не удалены). Логика контроля остатков может выдать ошибку: «Недостаточно товара, нужно 7, в наличии 5». Хотя на самом деле товара достаточно (10 единиц).

Чтобы избежать этой ситуации в современном коде, мы используем следующие подходы:

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

Выбор правильного режима удаления движений напрямую влияет на скорость работы системы и вероятность возникновения дедлоков (Deadlocks). Рассмотрим подробнее:

При режиме Удалять автоматически (Always) платформа делает лишнюю работу: она блокирует таблицы и удаляет данные еще до того, как основной код проведения начнет выполняться. Если проведение документа по какой-то причине прервется (например, сработает отказ из-за нехватки прав или ошибки в коде), СУБД придется делать откат (Rollback) операции удаления.

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

Практические рекомендации для разработчика

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

  1. Установите свойство Удаление движений в значение Удалять автоматически при отмене проведения.
  2. В процедуре ОбработкаПроведения установите свойство Записывать для нужных регистров в Истина.
  3. Если ваша логика проведения требует анализа текущих остатков, используйте «Новую методику проведения» (сначала записываем движения, потом проверяем остатки по регистру с учетом итогов) либо предварительно очищайте набор записей вручную.

Пример кода для эффективной перезаписи:


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

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

← На главную