Как изменить значение ячейки в табличном поле списка документов 1С

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

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

Разберем подробнее, почему возникает ошибка Поле объекта недоступно для записи, как правильно настраивать вывод данных в табличном поле и как избежать критического падения производительности при прокрутке списка.

Причины возникновения ошибок при редактировании строк списка

Проанализируем типовую ошибку, с которой сталкиваются разработчики при попытке записи данных в обработчике события списка:


Процедура ЖурналДокументовСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    Элемент.ТекущаяСтрока.СтатьяДвиженияДенежныхСредств = ДанныеСтроки.Ссылка.РасшифровкаПлатежа[0].СтатьяДвиженияДенежныхСредств;
КонецПроцедуры

При выполнении этого кода платформа генерирует исключение по нескольким причинам:

  1. Данные списка доступны только для чтения. Коллекции типа ЖурналДокументовСписок или ДокументСписок представляют собой динамическую выборку из базы данных. Поля этих объектов не предназначены для прямой модификации в интерфейсе.
  2. Обращение к пустой табличной части по индексу. Конструкция вида ...РасшифровкаПлатежа[0]... вызовет фатальную ошибку Индекс находится за границами массива, если у документа табличная часть не заполнена.
  3. Проблема производительности (N+1). Обращение через точку к табличной части (ДанныеСтроки.Ссылка.РасшифровкаПлатежа) заставляет платформу считывать весь документ целиком из базы данных для каждой видимой строки списка. Это приводит к зависанию интерфейса при пролистывании.

Способ 1. Вывод текста ячейки в событии ПриВыводеСтроки

Если требуется быстро отобразить данные без изменения структуры базы данных, мы не меняем сами данные в строке, а управляем визуальным оформлением ячейки через объект ОформлениеСтроки.

Посмотрим на пример корректного заполнения текста с проверкой заполненности табличной части:


Процедура ЖурналДокументовСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    // Проверяем наличие строк в табличной части перед обращением по индексу
    Если ДанныеСтроки.Ссылка.РасшифровкаПлатежа.Количество() > 0 Тогда
        Статья = ДанныеСтроки.Ссылка.РасшифровкаПлатежа[0].СтатьяДвиженияДенежныхСредств;
        ОформлениеСтроки.Ячейки.Статья.УстановитьТекст(Строка(Статья));
    КонецЕсли;

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

Если колонка в табличном поле не связана с данными (свойство Данные у колонки пустое), можно использовать свойство Значение или метод УстановитьЗначение(). Это позволит платформе самостоятельно сформировать представление ссылки:


Процедура ЖурналДокументовСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    Если ДанныеСтроки.Ссылка.РасшифровкаПлатежа.Количество() > 0 Тогда
        ОформлениеСтроки.Ячейки.Статья.Значение = ДанныеСтроки.Ссылка.РасшифровкаПлатежа[0].СтатьяДвиженияДенежныхСредств;
    КонецЕсли;

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

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

Способ 2. Оптимальная пакетная выборка в событии ПриПолученииДанных

Наиболее правильный с точки зрения производительности подход для обычных форм — использование события ПриПолученииДанных. Это событие вызывается один раз для всей пачки отображаемых на экране строк, что позволяет получить необходимые данные одним запросом к СУБД.

Разберем по шагам реализацию этого механизма:

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

Посмотрим на практический пример кода:


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

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

Альтернативные архитектурные решения

Выясним, какие еще подходы можно применить в зависимости от используемой архитектуры и требований к функционалу:

  1. Денормализация данных (для обычных форм). Если пользователям необходимо выполнять поиск, сортировку или устанавливать платформенный отбор по этой колонке, оформление ячеек не подойдет (данные в списке виртуальные). В таком случае правильным решением будет добавить реквизит в шапку документа, заполнять его при записи из первой строки табличной части и включить в графу журнала документов.
  2. Произвольный запрос динамического списка (для управляемых форм). В управляемом приложении подобные задачи решаются без программного кода отрисовки. Достаточно включить в свойствах динамического списка флаг ПроизвольныйЗапрос и соединить основную таблицу с подзапросом по табличной части документа, сгруппированным по МИНИМУМ(НомерСтроки).
← На главную