Почему запрос к регистру бухгалтерии не видит записи при проведении документа и как это исправить

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает ситуация, когда программисту необходимо проанализировать только что сформированные движения документа непосредственно в процессе его проведения. Однако при попытке выполнить запрос к виртуальным или физическим таблицам регистра (например, РегистрБухгалтерии.Хозрасчетный) результат оказывается пустым, хотя в отладке мы четко видим, что коллекция Движения заполнена проводками. Разберем детально, почему так происходит, и как правильно организовать работу с данными в этот момент.

Анализ причины: механизм транзакции и оперативная память

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

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

Решение 1: Работа с коллекцией движений в памяти (Рекомендуемое)

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


// Внутри процедуры ОбработкаПроведения
// Выгружаем движения регистра Хозрасчетный в таблицу значений
ТаблицаПроводок = Движения.Хозрасчетный.Выгрузить();

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

НайденныеСтроки = ТаблицаПроводок.НайтиСтроки(ПараметрыОтбора);

СуммаИтого = 0;
Для Каждого СтрокаПроводки Из НайденныеСтроки Цикл
    СуммаИтого = СуммаИтого + СтрокаПроводки.Сумма;
КонецЦикла;

Этот метод хорош тем, что он не создает лишней нагрузки на SQL-сервер и исключает риск возникновения взаимных блокировок (Deadlocks), так как мы работаем исключительно с локальными данными сеанса.

Решение 2: Использование менеджера временных таблиц

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

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

Посмотрим на пример кода:


ТаблицаДвижений = Движения.Хозрасчетный.Выгрузить();

МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Передаем таблицу в запрос
Запрос.Текст = 
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Движения ИЗ &ТЗ КАК ТЗ;
|ВЫБРАТЬ 
|   ВТ.СчетДт, 
|   ВТ.Сумма 
|ИЗ ВТ_Движения КАК ВТ 
|ГДЕ ВТ.СчетКт = &НужныйСчет";

Запрос.УстановитьПараметр("ТЗ", ТаблицаДвижений);
Запрос.УстановитьПараметр("НужныйСчет", ПланыСчетов.Хозрасчетный.Касса);

Результат = Запрос.Выполнить();

Решение 3: Принудительная запись набора записей

Существует еще один способ — заставить систему записать движения в базу данных прямо посреди транзакции, не дожидаясь окончания процедуры проведения. Для этого используется метод Записать() у конкретного набора записей. После этого вызова обычный запрос к таблицам регистра начнет "видеть" эти данные.

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


// Принудительно записываем движения в БД в рамках текущей транзакции
Движения.Хозрасчетный.Записать();

// Теперь ваш исходный запрос из сообщения сработает
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... ИЗ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(...)";
// Установка параметров...
Выборка = Запрос.Выполнить().Выбрать();

Обратите внимание, что если у документа в свойстве "Записывать выбранные" стоит значение "Записывать выбранные", то в конце процедуры проведения система попытается записать набор еще раз. Если вы уже вызвали Записать() вручную, убедитесь, что вы не очистили коллекцию и не изменили её состояние непреднамеренно.

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

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

Подведем итоги

Для эффективной и безопасной разработки в 1С следуйте этим правилам:

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

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

← На главную