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