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