Как исправить обрезание данных в колонке динамического списка 1С

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

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

Почему данные в колонке обрезаются?

Проанализируем ситуацию: когда мы добавляем в текст запроса динамического списка конструкцию "" КАК ВнутреннийНомер, платформа 1С выполняет автоматическое выведение типа (Type Inference). Поскольку в кавычках ничего нет, система резервирует под это поле минимально возможный объем памяти — строку длиной 1 символ. В результате, какую бы длинную строку мы ни пытались записать в это поле программно, в интерфейсе отобразится только первая буква.

Существует несколько способов решения этой проблемы, от простых до профессиональных и наиболее оптимизированных.

Способ 1: Явное типизирование через ВЫРАЗИТЬ

Это самый правильный и надежный метод с точки зрения описания схемы компоновки данных. Мы должны явно сообщить платформе, какую максимальную длину будет иметь наша строка. Для этого в тексте запроса динамического списка используем конструкцию ВЫРАЗИТЬ.

Вместо обычных кавычек напишем следующий код:

ВЫРАЗИТЬ("" КАК СТРОКА(100)) КАК ВнутреннийНомер

Важный момент: если указать неограниченную длину (СТРОКА(0)), это может привести к тому, что по данной колонке нельзя будет выполнять сортировку или группировку. Поэтому рекомендуется всегда указывать разумный предел длины, например 50, 100 или 250 символов.

Способ 2: Использование литерала с пробелами

Рассмотрим вариант, который иногда применяют в качестве «быстрого фикса». Если в запросе написать строку, состоящую из пробелов, платформа выделит длину, равную количеству этих пробелов:

" " КАК ВнутреннийНомер

Однако этот метод считается небрежным, так как его сложно поддерживать (трудно на глаз определить точное количество пробелов) и он менее надежен, чем явное использование ВЫРАЗИТЬ.

Оптимизация заполнения данных: избавляемся от проблемы N+1

Зачастую проблема обрезания символов — не единственная в таком коде. Рассмотрим пример из вопроса автора:


Для Каждого Строка Из Строки Цикл
    ДокСсылка = Строка.Значение.Данные.Ссылка;
    Если ДокСсылка.Метаданные().Реквизиты.Найти("Префикс") <> Неопределено Тогда
        Строка.Значение.Данные.ВнутреннийНомер = СокрЛП(ДокСсылка.ВнутреннийНомер) + "-" + СокрЛП(ДокСсылка.Префикс);
    КонецЕсли;    
КонецЦикла;

Такой подход содержит критическую ошибку производительности. При обращении к ДокСсылка.Префикс внутри цикла платформа выполняет отдельный SQL-запрос к базе данных для каждой строки списка. Если на экране отображается 30 строк, система сделает 30 лишних запросов. Это называется проблемой N+1 и приводит к «тормозам» при прокрутке списка.

Правильный алгоритм работы в ПриПолученииДанныхНаСервере

Разберем по шагам, как профессионально реализовать заполнение данных без лишней нагрузки на сервер:

  1. Сбор ссылок: Сначала соберем все ссылки на объекты из коллекции Строки в один массив.
  2. Пакетный запрос: Выполним один единственный запрос к базе данных, который получит нужные нам реквизиты (ВнутреннийНомер, Префикс) сразу для всех документов из массива.
  3. Использование соответствия: Поместим результат запроса в объект Соответствие, где ключом будет Ссылка, а значением — структура с данными.
  4. Заполнение: В цикле по коллекции Строки будем брать готовые значения из соответствия.

Посмотрим на пример реализации такого подхода:


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

КонецПроцедуры

Альтернатива: перенос логики в запрос динамического списка

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


ВЫБОР 
    КОГДА ТипДокумента = "Заказ" 
    ТОГДА ВнутреннийНомер + "-" + Префикс 
    ИНАЧЕ "" 
КОНЕЦ КАК ВнутреннийНомер

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

← На главную