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