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