Почему мы не можем напрямую сохранить табличную часть и как это сделать в 1С?

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

Приветствуем вас, коллеги-разработчики 1С! Наверняка каждый из нас сталкивался с задачей сохранения данных из табличной части формы или отчета, чтобы потом восстановить их при следующем открытии. Мы хотим, чтобы наши пользователи могли настроить отчет, заполнить какую-либо табличную часть и сохранить эти настройки, не вводя данные заново. Однако, при попытке прямого присваивания табличной части, мы обнаруживаем, что это не так просто. Давайте вместе разберем, почему это происходит и какие эффективные способы предлагает платформа 1С для решения этой задачи. Прямое сохранение объекта типа ТабличнаяЧасть, как правило, невозможно. Это связано с тем, что табличная часть является частью формы или объекта данных и не является самостоятельным сериализуемым объектом, который можно просто присвоить или поместить в хранилище. Для сохранения данных табличной части нам необходимо преобразовать их в более универсальный и сериализуемый формат, а затем уже работать с этим форматом. Мы рассмотрим несколько подходов к решению этой проблемы, начиная от самых простых и заканчивая более сложными, включающими работу с файлами и временными хранилищами.

Решение 1: Использование методов Выгрузить() и Загрузить() с промежуточной ТаблицейЗначений

Это один из самых распространенных и удобных способов работы с данными табличных частей. Платформа 1С предоставляет нам мощный механизм преобразования табличной части в объект типа ТаблицаЗначений и обратно.

Принцип работы

  1. Выгрузка данных: Мы используем метод Выгрузить() табличной части, чтобы получить ее содержимое в виде объекта ТаблицаЗначений. ТаблицаЗначений – это универсальный объект, который легко сериализуется и может быть сохранен в различных хранилищах (например, в структуре, соответствии, хранилище настроек или даже в реквизите типа ХранилищеЗначения).
  2. Сохранение ТаблицыЗначений: Полученную ТаблицуЗначений мы можем сохранить в любом подходящем месте, например, в реквизите формы, в пользовательских настройках, в структуре для дальнейшей передачи или в объекте, который будет сериализован.
  3. Загрузка данных: При восстановлении настроек мы извлекаем сохраненную ТаблицуЗначений и используем метод Загрузить() табличной части, чтобы поместить в нее данные.

Рассмотрим пример кода для сохранения:

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


// Предполагаем, что СписокКлиентов - это ТабличнаяЧасть
// и НастройкиВыгрузки - это Соответствие или Структура
НастройкиВыгрузки.Вставить("СписокКлиентов", СписокКлиентов.Выгрузить());

Здесь мы берем табличную часть СписокКлиентов, вызываем у нее метод Выгрузить(), который возвращает нам ТаблицуЗначений, и затем сохраняем эту ТаблицуЗначений под ключом "СписокКлиентов" в объекте НастройкиВыгрузки.

Пример кода для восстановления:

Для восстановления данных нам нужно получить сохраненную ТаблицуЗначений и загрузить ее обратно в табличную часть.


// Предполагаем, что НастройкиВыгрузки содержит сохраненную ТаблицуЗначений
// и СписокКлиентов - это ТабличнаяЧасть, которую нужно заполнить
Если НастройкиВыгрузки.Свойство("СписокКлиентов") Тогда
    СохраненныйСписокКлиентовТЗ = НастройкиВыгрузки.Получить("СписокКлиентов");
    Если ТипЗнч(СохраненныйСписокКлиентовТЗ) = Тип("ТаблицаЗначений") Тогда
        СписокКлиентов.Загрузить(СохраненныйСписокКлиентовТЗ);
    Иначе
        Сообщить("В настройках обнаружен некорректный тип данных для списка клиентов.");
    КонецЕсли;
КонецЕсли;

Обратите внимание: Важно убедиться, что извлеченное значение действительно является ТаблицейЗначений, прежде чем пытаться загрузить его в табличную часть. Это поможет избежать ошибок в случае некорректно сохраненных данных.

Решение 2: Сохранение табличной части в файл через временное хранилище

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

Общая схема процесса

  1. На стороне клиента: Пользователь инициирует сохранение или загрузку файла.
  2. На стороне сервера: Происходит основная работа по преобразованию данных:
    1. Табличная часть (тчИД) выгружается в ТаблицуЗначений с помощью метода Выгрузить().
    2. ТаблицаЗначений преобразуется в строковое представление с использованием ЗначениеВСтрокуВнутр().
    3. Строковое представление кодируется в ДвоичныеДанные (например, в кодировке "windows-1251") с помощью ПолучитьДвоичныеДанныеИзСтроки().
    4. ДвоичныеДанные помещаются во ВременноеХранилище на сервере с помощью ПоместитьВоВременноеХранилище().
  3. Снова на стороне клиента: Файл скачивается с сервера на диск пользователя или загружается с диска пользователя на сервер.

Рассмотрим подробнее этапы сохранения:

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

1. На стороне клиента: Инициируем запись файла


&НаКлиенте
Процедура Команда2_ЗаписатьФайл(Команда)
    // Проверяем, заполнена ли табличная часть
    Если Объект.тчИД.Количество() = 0 Тогда
        ПоказатьПредупреждение(,"НЕ заполнена табл. часть! Нажмите [Подготовить]", 5);
        Возврат;
    КонецЕсли;
    
    // Вызываем серверную процедуру для подготовки данных
    Команда2_ЗаписатьФайлНаСервере();
    
    // Определяем имя файла для сохранения
    ИмяФайла = "ID_TovarOzon.dat";
    
    // Получаем адрес временного файла, который был подготовлен на сервере
    АдресФайлаДанныхВХранилище = Объект.АдресВремФайла; 
    
    // Начинаем получение файла с сервера на диск пользователя
    НачатьПолучениеФайлаССервера(АдресФайлаДанныхВХранилище, ИмяФайла); 
КонецПроцедуры

2. На стороне сервера: Подготавливаем данные для сохранения


&НаСервере
Процедура Команда2_ЗаписатьФайлНаСервере()
    // Получаем объект обработки из реквизита формы
    ОбъектОбр = РеквизитФормыВЗначение("Объект");
    
    // Шаг 1: Табличная часть -> ТаблицаЗначений -> СтрокаВнутр
    стрТаб = ЗначениеВСтрокуВнутр(ОбъектОбр.тчИД.Выгрузить());
    
    // Шаг 2: СтрокаВнутр -> ДвоичныеДанные
    // Используем кодировку "windows-1251" для корректной работы с двоичными данными
    стрТ64 = ПолучитьДвоичныеДанныеИзСтроки(стрТаб, "windows-1251");
    
    // Шаг 3: ДвоичныеДанные -> ХранилищеЗначений (временное)
    // Помещаем двоичные данные во временное хранилище на сервере
    АдресФайлаДанных = ПоместитьВоВременноеХранилище(стрТ64, УникальныйИдентификатор);
    
    // Сохраняем адрес временного хранилища в реквизит формы для последующего доступа на клиенте
    ОбъектОбр.АдресВремФайла = АдресФайлаДанных;
    
    // Обновляем реквизит формы
    ЗначениеВРеквизитФормы(ОбъектОбр, "Объект"); 
КонецПроцедуры

Рассмотрим подробнее этапы восстановления:

Для восстановления данных из файла мы выполняем действия в обратном порядке.

1. На стороне клиента: Инициируем чтение файла


&НаКлиенте
Процедура Команда3_ПрочитатьФайл(Команда)
    // Создаем описание оповещения для обработки результата выбора файла
    ОписаниеОповещения = Новый ОписаниеОповещения("ВыбратьФайлID_TovarOzon", ЭтотОбъект);
    
    // Начинаем помещение файла с диска пользователя на сервер во временное хранилище
    НачатьПомещениеФайлаНаСервер(ОписаниеОповещения,,,,, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ВыбратьФайлID_TovarOzon(Результат, ДополнительныеПараметры) Экспорт
    // Проверяем, был ли выбран файл
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем серверную процедуру для чтения данных из временного хранилища
    Команда3Х_ПрочитатьФайлНаСервере(Результат.Адрес);
КонецПроцедуры

2. На стороне сервера: Читаем данные и загружаем в табличную часть


&НаСервере
Процедура Команда3Х_ПрочитатьФайлНаСервере(пИмяФайла)
    // Шаг 1: ХранилищеЗначений (временное) -> ДвоичныеДанные
    // Получаем двоичные данные из временного хранилища по переданному адресу
    ПолученноеДвоичД = ПолучитьИзВременногоХранилища(пИмяФайла);
    
    // Шаг 2: ДвоичныеДанные -> СтрокаВнутр
    // Преобразуем двоичные данные обратно в строковое представление
    Строка64 = ПолучитьСтрокуИзДвоичныхДанных(ПолученноеДвоичД, "windows-1251");
    
    // Шаг 3: СтрокаВнутр -> ТаблицаЗначений
    // Восстанавливаем ТаблицуЗначений из строкового представления
    ПолученноеЗначение = ЗначениеИзСтрокиВнутр(Строка64);
    
    // Проверяем тип полученного значения
    Если ТипЗнч(ПолученноеЗначение) = Тип("ТаблицаЗначений") Тогда
        // Если это ТаблицаЗначений, загружаем ее в табличную часть формы
        ОбъектОбр = РеквизитФормыВЗначение("Объект");
        ОбъектОбр.тчИД.Загрузить(ПолученноеЗначение);
        ЗначениеВРеквизитФормы(ОбъектОбр, "Объект");
    Иначе // Формат файла не опознан
        Сообщить("НЕизвестный тип значения в файле: " + пИмяФайла + ", " + ТипЗнч(ПолученноеЗначение));
    КонецЕсли;
КонецПроцедуры

Важный момент: Как видим из примера, основная сложность заключается в правильном преобразовании данных из одного формата в другой, особенно при работе с ДвоичнымиДанными и строковыми представлениями. Необходимо тщательно следить за кодировкой (например, "windows-1251"), чтобы избежать повреждения данных при преобразовании.

Решение 3: Использование стандартных хранилищ настроек платформы

Платформа 1С:Предприятие предоставляет встроенные механизмы для сохранения пользовательских настроек, которые идеально подходят для хранения сериализуемых объектов, таких как ТаблицаЗначений. Мы рассмотрим ХранилищеОбщихНастроек и ХранилищеНастроекПользователя.

ХранилищеОбщихНастроек

Этот механизм позволяет сохранять произвольные настройки как для текущего пользователя, так и для всех пользователей или определенной группы. Настройки хранятся на сервере и доступны в любой момент времени.

Сохранение ТаблицыЗначений в ХранилищеОбщихНастроек:

Мы сначала выгружаем табличную часть в ТаблицуЗначений, а затем помещаем эту таблицу в хранилище.


// Предположим, у нас есть табличная часть "ТабличнаяЧастьОтчета"
// и мы хотим сохранить ее в общих настройках под именем "МоиДанныеОтчета"

// Шаг 1: Выгружаем табличную часть в ТаблицуЗначений
ТаблицаЗначенийДляСохранения = ТабличнаяЧастьОтчета.Выгрузить();

// Шаг 2: Создаем структуру для сохранения, если нужно
СтруктураНастроек = Новый Структура("СписокДанных", ТаблицаЗначенийДляСохранения);

// Шаг 3: Сохраняем ТаблицуЗначений (или структуру с ней) в ХранилищеОбщихНастроек
// ИмяНастройки - уникальное имя для нашей настройки
// ИдентификаторОбъекта - можно привязать к конкретному отчету/обработке
// ОписаниеНастройки - текстовое описание
// ДляВсехПользователей - Истина/Ложь
ХранилищеОбщихНастроек.Сохранить(
    "МоиНастройкиОтчета",                   // Имя настройки
    СтруктураНастроек,                      // Значение (ТаблицаЗначений или Структура с ней)
    УникальныйИдентификаторОтчета,          // Идентификатор объекта, к которому относится настройка
    "Настройки списка данных отчета",       // Описание
    Ложь                                    // ДляВсехПользователей (сохраняем для текущего)
);

Загрузка ТаблицыЗначений из ХранилищеОбщихНастроек:


// ИмяНастройки и ИдентификаторОбъекта должны совпадать с теми, что использовались при сохранении
СохраненныеНастройки = ХранилищеОбщихНастроек.Загрузить(
    "МоиНастройкиОтчета",
    УникальныйИдентификаторОтчета
);

Если СохраненныеНастройки <> Неопределено Тогда
    // Получаем ТаблицуЗначений из структуры
    ТаблицаЗначенийЗагруженная = СохраненныеНастройки.СписокДанных;
    
    // Загружаем данные обратно в табличную часть
    Если ТипЗнч(ТаблицаЗначенийЗагруженная) = Тип("ТаблицаЗначений") Тогда
        ТабличнаяЧастьОтчета.Загрузить(ТаблицаЗначенийЗагруженная);
    Иначе
        Сообщить("Ошибка: Сохраненные данные не являются ТаблицейЗначений.");
    КонецЕсли;
Иначе
    Сообщить("Настройки отчета не найдены.");
КонецЕсли;

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

Заключение

Мы выяснили, что прямая работа с объектом ТабличнаяЧасть для сохранения его состояния невозможна. Вместо этого, мы используем промежуточный объект ТаблицаЗначений, который является универсальным и легко сериализуемым. Далее эту ТаблицуЗначений можно сохранить различными способами:

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

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

Надеемся, это подробное руководство поможет вам эффективно работать с табличными частями в ваших решениях на 1С!

← К списку