Как реализовать проведение документа через запрос в 1С:Предприятие 8?

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

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

Почему проведение запросом эффективнее перебора строк?

Прежде чем мы приступим к технической реализации, давайте проанализируем, почему «запросный» метод считается стандартом разработки. Когда мы используем цикл Для Каждого Строка ИЗ ТабличнаяЧасть Цикл, система выполняет операции последовательно для каждой строки. Если в документе 500 строк, то программа совершит 500 мелких обращений к данным. В случае использования запроса, вся обработка данных происходит на стороне сервера базы данных (SQL) одним блоком, что значительно сокращает время выполнения транзакции.

Основные преимущества:

Подготовка к реализации: работа с внешней обработкой

Как справедливо заметили участники обсуждения, новичку не стоит сразу вносить изменения в модуль документа. Разберем по шагам, как подготовиться. Мы рекомендуем создать внешнюю обработку, чтобы «потренироваться» в написании запросов. Это обезопасит конфигурацию от ошибок, которые могут привести к зависанию проведения.

Рассмотрим пример кода, который можно использовать в серверной процедуре обработки для проверки ваших навыков работы с объектом Запрос:


// Пример тренировочного кода во внешней обработке
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Наименование КАК Наименование,
    |   Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура";

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

Реализация проведения в модуле документа

Теперь перейдем к основной задаче: замене цикла в процедуре ОбработкаПроведения. Наша цель — получить данные из документа запросом и «загрузить» их в набор записей регистра накопления. Проанализируем алгоритм действий.

Шаг 1. Создание запроса к данным документа.

Важно помнить, что запрос должен обращаться к данным документа, который уже записан в базу. В качестве параметра мы будем передавать Ссылка текущего документа.


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

Запрос.УстановитьПараметр("Ссылка", Ссылка);

Шаг 2. Использование метода Загрузить().

Вместо того чтобы вручную добавлять каждую строку в Движения.ИмяРегистра.Добавить(), мы воспользуемся мощным методом Загрузить(). Этот метод принимает таблицу значений и заменяет текущие записи набора записей регистра данными из этой таблицы.

Важное условие: имена колонок в результате запроса (псевдонимы) должны строго совпадать с именами измерений и ресурсов регистра накопления (например, Номенклатура, Склад, Количество).


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

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

Профессиональный нюанс: Новая методика проведения

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

Почему это лучше? Это минимизирует время блокировки таблиц базы данных. Мы блокируем только те записи, которые реально меняются, и делаем это в самый последний момент.

Проанализируем структуру такой процедуры:

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

Использование блокировок данных

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


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиТоваров");
ЭлементБлокировки.УстановитьПараметр("Склад", СкладИзШапки);
ЭлементБлокировки.ИсточникДанных = ТабличнаяЧастьТовары;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();

Этот код гарантирует, что пока ваш документ проводится, никакая другая операция не изменит остатки по этим конкретным товарам.

Заключение

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

← На главную