При разработке на платформе 1С:Предприятие 8 часто возникает ситуация, когда дерево значений (ДеревоЗначений) формируется динамически, например, через систему компоновки данных (СКД). Одной из типичных проблем является невозможность изменить значение в конкретной ячейке. Вы пытаетесь присвоить строку, но значение остается NULL, и система не выдает ошибок. В этой статье мы подробно разберем, почему так происходит и как правильно изменить структуру дерева для корректной работы с данными.
Разберем ситуацию: вы получили дерево значений с помощью ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений. В некоторых колонках вместо ожидаемых данных отображается NULL. Когда вы пытаетесь программно записать туда значение:
Данные.Строки[0].ПараметрыДанныхДолжность = "Менеджер";
Ничего не происходит. Это случается потому, что у колонки дерева значений уже жестко определен тип данных. Если в результате запроса или компоновки в этой колонке во всех строках оказался NULL, платформа 1С зачастую создает колонку с единственным допустимым типом — NULL. Попытка записать строку в поле, которое «умеет» хранить только NULL, игнорируется платформой.
Важно понимать, что свойство ТипЗначения у объекта КолонкаДереваЗначений доступно только для чтения. Мы не можем просто взять и заменить ОписаниеТипов существующей колонки. Нам придется использовать обходные пути.
Проанализируем самый прямой способ решения задачи: если тип существующей колонки нас не устраивает, мы должны ее удалить и создать заново с нужным типом. Рассмотрим пример кода, который решает эту задачу:
// 1. Подготовим новое описание типа (например, Строка длиной 100)
КвалификаторыСтроки = Новый КвалификаторыСтроки(100);
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка", , КвалификаторыСтроки);
// 2. Определим имя проблемной колонки
ИмяКолонки = "ПараметрыДанныхДолжностьРаботникаКадровойСлужбы";
// 3. Удалим старую колонку, тип которой нас не устраивает
Данные.Колонки.Удалить(ИмяКолонки);
// 4. Добавим новую колонку с тем же именем, но правильным типом
Данные.Колонки.Добавить(ИмяКолонки, ОписаниеТипаСтрока);
// 5. Теперь мы можем спокойно присваивать значения
НоваяСтрока = Данные.Строки.Добавить();
НоваяСтрока[ИмяКолонки] = "Тест";
Этот метод прост, но имеет один недостаток: при использовании метода Добавить() новая колонка всегда помещается в самый конец коллекции колонок. Если порядок полей в дереве критичен для отображения на форме, этот способ может нарушить визуальную структуру.
Рассмотрим подробнее, как заменить колонку, сохранив ее индекс (позицию) в дереве. Это позволит избежать «прыжков» колонок в интерфейсе пользователя. Разберем по шагам:
Вставить().
ИмяКолонки = "ВашаКолонка";
ИндексКолонки = Данные.Колонки.Индекс(Данные.Колонки[ИмяКолонки]);
// Подготовка типа
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
// Пересоздание
Данные.Колонки.Удалить(ИндексКолонки);
Данные.Колонки.Вставить(ИндексКолонки, ИмяКолонки, ОписаниеТипаЧисло, "Заголовок колонки");
Обратите внимание: Если в старой колонке уже были какие-то данные (не только NULL), при удалении колонки они будут безвозвратно потеряны. В таком случае перед удалением данные нужно скопировать во временный массив или таблицу.
Зачастую правильнее не исправлять уже готовое дерево, а заставить систему компоновки данных сразу отдавать нужные типы. Посмотрим на ситуацию: если СКД видит, что поле пустое, она не понимает, какой тип данных там должен быть. Мы можем «подсказать» ей это в схеме компоновки. Для удобной программной настройки схемы компоновки можно использовать библиотеку для упрощения программного создания и настройки СКД.
Рассмотрим основные приемы в консоли СКД или конфигураторе:
ЕСТЬNULL(ВашеПоле, ""). Это принудительно типизирует колонку как строку, и в дереве значений она уже не будет иметь тип NULL.ВЫРАЗИТЬ(Поле КАК СТРОКА(150)).Если дерево значений имеет сложную иерархию и нам нужно изменить тип колонки, в которой уже есть данные в некоторых узлах, нам потребуется рекурсивный алгоритм. Проанализируем пример функции, которая помогает перенести данные при смене типа:
Процедура ОбновитьДанныеВКолонке(СтрокиДерева, ИмяСтаройКолонки, ИмяНовойКолонки)
Для Каждого Строка Из СтрокиДерева Цикл
// Копируем значение (если типы совместимы или для последующего преобразования)
Строка[ИмяНовойКолонки] = Строка[ИмяСтаройКолонки];
// Рекурсивно заходим в подчиненные строки
ОбновитьДанныеВКолонке(Строка.Строки, ИмяСтаройКолонки, ИмяНовойКолонки);
КонецЦикла;
КонецПроцедуры
Алгоритм действий будет таким: создаем временную колонку Имя_Врем, переносим в нее данные рекурсией, удаляем старую, создаем новую с правильным типом и переносим данные обратно.
Проанализируем важный нюанс: если ваше дерево значений связано с реквизитом формы (типа ДанныеФормыДерево), то простое манипулирование объектом ДеревоЗначений на сервере не обновит колонки на форме автоматически. При необходимости можно изучить примеры программного формирования СКД и создания элементов управляемой формы.
Если вы программно изменили состав колонок у ДеревоЗначений, вам необходимо:
ЗначениеВРеквизитФормы(ВашеДеревоОбъект, "ИмяРеквизитаФормы").ИзменитьРеквизиты() для добавления новых путей к данным, а затем программно создавать элементы управления (колонки таблицы формы).Резюмируем: Проблема записи в дерево значений чаще всего кроется в жесткой типизации колонок. Не бойтесь удалять и добавлять колонки заново — это стандартная практика для динамической работы с коллекциями в 1С. Однако всегда старайтесь решить проблему на уровне запроса или настроек СКД, так как это более производительный и «чистый» способ разработки.