При разработке отчетов и обработок в платформе 1С:Предприятие 7.7 начинающие разработчики часто сталкиваются с ситуацией, когда попытка вывести несколько полей выборки запроса в одну строку через оператор сложения + приводит к неожиданным результатам. Например, выводится только первое значение, а второе полностью пропадает из окна сообщений, либо возвращается ошибка несовпадения типов.
Проанализируем конкретный пример кода, в котором возникла подобная проблема:
Процедура Расходные()
ВыбНачПериода = ТекущаяДата() - 29;
ВыбКонПериода = ТекущаяДата() + 2;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ВыбНачПериода по ВыбКонПериода;
|РасходнаяНакладная = Документ.РасходнаяНакладная.ТекущийДокумент;
|Товар = Документ.РасходнаяНакладная.Товар;
|НомерСтроки = Документ.РасходнаяНакладная.НомерСтроки;
|Группировка РасходнаяНакладная;
|Группировка НомерСтроки;
|Функция Колво = Счётчик();
|";
Запрос.Выполнить(ТекстЗапроса);
Пока Запрос.Группировка(1) = 1 Цикл
Сообщить(Запрос.РасходнаяНакладная + Запрос.Колво); // Количество не выводится
Пока Запрос.Группировка(2) = 1 Цикл
Сообщить(Запрос.Товар.Наименование + Запрос.НомерСтроки); // Номер строки не виден
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Выясним причину, почему данные отображаются некорректно. В платформе 1С 7.7 такое поведение обусловлено двумя независимыми механизмами:
Запрос.РасходнаяНакладная типа «Документ»), платформа пытается применить операцию сложения к объекту и числу Запрос.Колво. Поскольку операция сложения документа с числом не определена, выражение не может быть корректно приведено к строке без явного указания строкового контекста.Наименование) в 1С 7.7 имеют строго фиксированную длину в метаданных (например, 50, 100 или 150 символов). Если наименование товара короче максимальной длины, платформа дополняет его пробелами справа. При сложении Запрос.Товар.Наименование + Запрос.НомерСтроки число приводится к строке и дописывается в самый конец после десятков хвостовых пробелов. В результате номер строки физически присутствует, но уходит далеко за пределы видимой области окна сообщений.Разберем самый простой способ решения проблемы типизации. Чтобы платформа интерпретировала оператор + как конкатенацию строк, первым операндом необходимо поставить строковый литерал (хотя бы пустую строку ""). В этом случае все последующие операнды автоматически преобразуются в их строковое представление:
// Добавляем пустую строку или строковый разделитель первым операндом:
Сообщить("" + Запрос.РасходнаяНакладная + " : " + Запрос.Колво);
Чтобы строковые реквизиты справочников не сдвигали последующий текст за экран, необходимо удалять незначащие пробелы с помощью встроенных функций СокрЛП() (сокращение слева и справа) или СокрП() (сокращение справа):
// Очищаем наименование от хвостовых пробелов:
Сообщить("Товар: " + СокрЛП(Запрос.Товар.Наименование) + ", строка: " + Запрос.НомерСтроки);
Рассмотрим более надежный и читаемый способ форматирования сложных строк в 1С 7.7 — использование встроенной функции Шаблон(). Внутри строки-шаблона выражения помещаются в квадратные скобки [...], автоматически вычисляются и преобразуются к строковому типу без необходимости ручной расстановки операторов сложения:
Сообщить(Шаблон("[Запрос.РасходнаяНакладная] (Всего строк: [Запрос.Колво])"));
Сообщить(Шаблон("Товар: [СокрЛП(Запрос.Товар.Наименование)], строка №[Запрос.НомерСтроки]"));
Если требуется строго контролировать типы данных и избежать неявных преобразований, рекомендуется применять функцию Строка() к каждому нестроковому операнду:
Сообщить(Строка(Запрос.РасходнаяНакладная) + " - " + Строка(Запрос.Колво));
Обратим внимание на важную деталь производительности: обращение через точку к реквизитам объектов внутри цикла обхода (Запрос.Товар.Наименование) заставляет платформу выполнять дополнительное чтение объекта из базы данных на каждом шаге цикла. Чтобы ускорить выполнение кода, строковые поля следует выносить непосредственно в тело запроса:
Процедура РасходныеОптимизированная()
ВыбНачПериода = ТекущаяДата() - 29;
ВыбКонПериода = ТекущаяДата() + 2;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ВыбНачПериода по ВыбКонПериода;
|РасходнаяНакладная = Документ.РасходнаяНакладная.ТекущийДокумент;
|Товар = Документ.РасходнаяНакладная.Товар;
|ТоварНаименование = Документ.РасходнаяНакладная.Товар.Наименование;
|НомерСтроки = Документ.РасходнаяНакладная.НомерСтроки;
|Группировка РасходнаяНакладная;
|Группировка НомерСтроки;
|Функция Колво = Счётчик();
|";
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
Пока Запрос.Группировка(1) = 1 Цикл
Сообщить(Шаблон("[Запрос.РасходнаяНакладная] (Количество строк: [Запрос.Колво])"));
Пока Запрос.Группировка(2) = 1 Цикл
Сообщить(Шаблон("Товар: [СокрЛП(Запрос.ТоварНаименование)], строка №[Запрос.НомерСтроки]"));
КонецЦикла;
КонецЦикла;
КонецПроцедуры