При интеграции 1С со сторонними сервисами (например, телефонией Бинотел) разработчики часто сталкиваются с задачей получения данных по API в формате JSON и их последующей выгрузкой в табличную часть документа. Рассмотрим классическую ситуацию: мы получаем массив записей (например, историю звонков) и хотим поместить каждую запись в отдельную строку табличной части. Разберем по шагам, как избежать архитектурных ошибок, оптимизировать код и использовать встроенные механизмы платформы.
Часто начинающие программисты пытаются для каждой записи из JSON создавать отдельную локальную таблицу значений (Новый ТаблицаЗначений), заполнять ее, а затем переносить данные в табличную часть документа. Проанализируем, почему этот подход не является оптимальным:
ТаблицаЗначений в цикле для каждой записи — это лишняя трата ресурсов системы.Посмотрим на более изящные и правильные способы решения этой задачи.
Если имена колонок табличной части документа полностью соответствуют ключам структуры или соответствия, полученным из JSON, мы можем заполнять строки табличной части внутри цикла обхода входящих данных. Рассмотрим пример, где мы обходим данные одного звонка:
&НаСервере
Процедура ЧтениеДанныхЗвонков(ТекСтрокаЗвонок)
СтрокаТаблицыЗвонков = Объект.ТаблицаЗвонков.Добавить();
Для Каждого ТекСтрокаДанныеЗвонка Из ТекСтрокаЗвонок.Значение Цикл
// Обращаемся к колонке табличной части по имени ключа
СтрокаТаблицыЗвонков[ТекСтрокаДанныеЗвонка.Ключ] = ТекСтрокаДанныеЗвонка.Значение;
КонецЦикла;
КонецПроцедуры
Если имена не совпадают, мы можем явно указывать соответствие колонок:
&НаСервере
Процедура ЧтениеДанныхЗвонков(ТекСтрокаЗвонок)
СтрокаТаблицыЗвонков = Объект.ТаблицаЗвонков.Добавить();
СтрокаТаблицыЗвонков.Телефон = ТекСтрокаЗвонок["phone"];
СтрокаТаблицыЗвонков.Длительность = ТекСтрокаЗвонок["duration"];
КонецПроцедуры
Платформа 1С предоставляет мощный встроенный метод ЗаполнитьЗначенияСвойств. Он позволяет скопировать значения из структуры (полученной из JSON) прямо в строку табличной части одной строкой кода. Главное условие — ключи структуры должны совпадать с именами колонок. Посмотрим на переработанный пример основной процедуры получения звонков:
&НаСервере
Процедура КомандаПолучитьЗвонкиНаСервере()
ДокументОбъект = РеквизитФормыВЗначение("Объект");
// Получение данных по API
startTime = ДокументОбъект.ПолучитьUnixTS(Объект.startTime);
stopTime = ДокументОбъект.ПолучитьUnixTS(Объект.stopTime);
ПолучитьЗвонки = ДокументОбъект.IncomingCallsForPeriod(Объект.key, Объект.secret, startTime, stopTime);
Текст = Новый ЧтениеТекста(ПолучитьЗвонки, КодировкаТекста.UTF8);
СтруктураJSON = ДокументОбъект.ПрочитатьJSON_API(Текст.Прочитать(), Неопределено);
СтруктураЗвонков = Неопределено;
// Используем Свойство() вместо Попытка...Исключение (об этом ниже)
Если Не СтруктураJSON.Свойство("callDetails", СтруктураЗвонков) Тогда
Возврат;
КонецЕсли;
// Очищаем табличную часть перед заполнением
Объект.ТаблицаЗвонков.Очистить();
// Обходим каждый звонок и заполняем ТЧ
Для Каждого Запись Из СтруктураЗвонков Цикл
СтрокаТаблицыЗвонков = Объект.ТаблицаЗвонков.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаТаблицыЗвонков, Запись);
// Дозаполнение свойств, которых нет в JSON
СтрокаТаблицыЗвонков.isNewCall = Истина;
КонецЦикла;
КонецПроцедуры
Если API возвращает сотни или тысячи записей, добавление строк в цикле через Добавить() может замедлить работу интерфейса и сервера. Проанализируем, как использовать метод Загрузить(). Мы выгрузим пустую структуру табличной части в Таблицу Значений, заполним ее в памяти, а затем загрузим в объект целиком:
// 1. Выгружаем только структуру колонок ТЧ (передаем пустой массив)
ТаблицаДляЗагрузки = Объект.ТаблицаЗвонков.Выгрузить(Новый Массив);
// 2. Заполняем таблицу значений в памяти
Для Каждого Запись Из СтруктураЗвонков Цикл
НоваяСтрока = ТаблицаДляЗагрузки.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Запись);
КонецЦикла;
// 3. Загружаем всю таблицу в документ одним действием
Объект.ТаблицаЗвонков.Загрузить(ТаблицаДляЗагрузки);
Разберем подробнее неочевидные нюансы при работе с JSON и объектами платформы 1С, которые помогут сделать ваш код надежным и профессиональным:
callDetails) — это антипаттерн. Вызов исключения является ресурсоемкой операцией. Гораздо быстрее и правильнее использовать метод Свойство(), как было показано в коде выше.Очистить() для табличной части (Объект.ТаблицаЗвонков.Очистить()). Это защитит от дублирования строк при повторном нажатии пользователем кнопки запроса.ПрочитатьJSON) второй параметр часто оставляют пустым (Неопределено). Этот параметр предназначен для имени функции восстановления. В ней вы можете "на лету" преобразовывать ключи. Если API возвращает call_duration, а вам нужно Длительность, функция восстановления может переименовать ключи или преобразовать формат дат (Unix Timestamp в тип Дата) еще до того, как данные попадут в ваш основной алгоритм.ЗаполнитьЗначенияСвойств копирует данные "как есть". Если сторонний сервис вернет число как строку (например, "120"), а ваша колонка имеет строгий тип Число, значение может не установиться. Всегда контролируйте приведение базовых типов при работе со внешними API.