При разработке в среде 1С:ERP или 1С:Управление холдингом часто возникает задача проанализировать существующие движения документа непосредственно в момент установки пометки на удаление. Например, это может потребоваться для корректировки связанных регистров, которые не подчинены документу напрямую, или для логгирования удаляемых данных. Однако разработчики часто сталкиваются с тем, что в обработчике ПередЗаписью коллекция Движения выглядит пустой, хотя документ проведен и записи в базе данных точно есть. Разберем подробно, почему так происходит и как правильно получить эти данные.
Для начала проанализируем, как платформа 1С работает с объектом документа. Когда мы открываем форму документа или получаем объект программно, система считывает данные основной таблицы документа (реквизиты, табличные части). Однако движения по регистрам накопления, сведений или бухгалтерии не загружаются в оперативную память автоматически вместе с документом. Это сделано для экономии ресурсов: документов в базе миллионы, и загружать все их движения при каждом чтении объекта было бы крайне неэффективно.
В событии ПередЗаписью коллекция Движения содержит объекты типа НаборЗаписей. В этот момент они являются инициализированными, но «пустыми» (количество строк равно нулю), так как обращение к базе данных за ними еще не произошло. Даже если у документа установлено свойство Удаление движений в значение Не удалять автоматически, это не заставляет платформу считывать записи заранее.
Самый простой и правильный способ получить текущие движения документа в модуле объекта — это принудительно заставить платформу считать их из базы данных. Для этого у каждого набора записей в коллекции Движения существует метод Прочитать(). Рассмотрим по шагам, как это реализовать в коде:
Разберем пример кода, который можно разместить в процедуре ПередЗаписью модуля документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем, что документ помечается на удаление
Если ЭтотОбъект.ПометкаУдаления И ЭтотОбъект.Ссылка.Проведен Тогда
// Обращаемся к конкретному регистру
НаборДвижений = Движения.МойСамописныйРегистр;
// Принудительно считываем данные из БД в оперативную память
НаборДвижений.Прочитать();
// Теперь мы можем проанализировать движения
Если НаборДвижений.Количество() > 0 Тогда
Для Каждого СтрокаДвижения Из НаборДвижений Цикл
// Реализуем логику обработки существующих записей
Сообщить("Найдено движение по аналитике: " + СтрокаДвижения.Аналитика);
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важный нюанс: После вызова метода Прочитать() коллекция наполнится данными, которые физически записаны в базе в данный момент. Если в этом же обработчике вы планируете очистить движения, помните, что установка НаборДвижений.Записывать = Истина при пустом наборе (после того, как вы его обработали) приведет к их удалению при фиксации транзакции.
Иногда использование метода Прочитать() избыточно, особенно если вам нужны не все поля регистра или требуется агрегированная информация (например, суммы). В этом случае эффективнее выполнить запрос к базе данных. Проанализируем ситуацию: в момент выполнения ПередЗаписью транзакция уже открыта, но старые данные в таблицах регистра еще не изменены платформой. Мы можем получить их по Регистратору.
Рассмотрим пример реализации через запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МойРегистр.Сумма КАК Сумма,
| МойРегистр.Номенклатура КАК Номенклатура
|ИЗ
| РегистрНакопления.МойСамописныйРегистр КАК МойРегистр
|ГДЕ
| МойРегистр.Регистратор = &Регистратор";
Запрос.УстановитьПараметр("Регистратор", ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
КонецЕсли;
Преимущество этого метода в том, что вы не нагружаете память сервера 1С всем набором записей, если вам нужны только определенные колонки. Кроме того, это единственный надежный способ, если вы работаете в подписке на событие, где коллекция Движения может вести себя специфически в зависимости от контекста вызова.
В конфигурациях на базе ERP (таких как 1С:УХ или 1С:КА) механизмы проведения и отмены проведения сильно переработаны по сравнению с «простыми» конфигурациями. Выясним, на что стоит обратить внимание:
ПроведениеСервер). Эти подписки могут программно очищать наборы записей. Поэтому проверять движения нужно в самом начале цепочки событий ПередЗаписью.ДополнительныеСвойства. Туда могут помещаться таблицы с движениями, которые система планирует удалить или изменить. Проверьте содержимое этой структуры в отладке — возможно, нужные данные уже подготовлены системой для вас.Прочитать(), вы видите состояние базы до фиксации текущих изменений. Если же вы попытаетесь получить данные в событии ПриЗаписи, и типовой механизм уже успел очистить движения, то запрос может вернуть пустой результат, так как в рамках транзакции записи уже помечены как удаленные.Если вы установили точку останова в ПередЗаписью, используйте окно Вычислить выражение (Shift+F9). Не ограничивайтесь просмотром количества строк в коллекции. Попробуйте прямо в окне вычисления вызвать Движения.ИмяВашегоРегистра.Прочитать(), а затем снова проверьте количество строк. Если после вызова метода Прочитать() строки появились — значит, проблема была исключительно в ленивой загрузке данных платформой.
Если же даже после Прочитать() набор пуст, значит одно из двух: либо документ действительно не делал движений в этот регистр, либо какая-то подписка на событие ПередЗаписью сработала раньше вашего кода и уже успела очистить и записать пустой набор. В этом случае проверьте приоритет подписок в конфигураторе.
Таким образом, для гарантированного доступа к движениям при удалении документа мы рекомендуем использовать комбинацию проверки режима записи и метода Прочитать(), что обеспечивает наиболее стабильный результат в типовых конфигурациях 1С.