Перенос таблицы значений между клиентом и сервером

Всем привет.
Бывают такие моменты, когда необходимо таблицу значений передать с сервера на клиент, увы, Мутабельные значения и т.д.
В тоже время есть возможность перекидывать все это добро через Хранилище, чем собственно разработчики часто пользуются.
Но сегодня я бы хотел вынести на Вашу критику вот такой пример переноса.

Сильно не пинайте.

Все мы сталкивались с ситуацией, когда необходимо с сервера передать данные на клиент. И далеко не всегда это примитивные типы.

Об одном из таких типов я бы сегодня и хотел поговорить.

Речь сегодня о таблицы значений.

Данный тип является мутабельным и при попытке выполнить это действия мы получим ошибку:

{Справочник.НастройкиЗаполненияОбъектов1СДокументооборота.МодульОбъекта(33)}: Ошибка при вызове метода контекста (ПолучитьПрокси)
Прокси = ИнтеграцияС1СДокументооборотВызовСервера.ПолучитьПрокси();
по причине:
Попытка передачи мутабельного значения результата метода ПолучитьПрокси ().

(текст ошибки в каждом случае свой)

 

Сегодня я выношу на Вашу критику и обозрение один из вариантов решения этой проблемы, а именно преобразование в Массив(может передаваться) из структур и обратно в таблицу.

 

Функция «ПреобразоватьТаблицуЗначенийВМассив» выполняется на сервере перед передачей данных, а «ПреобразоватьМассивВТаблицуЗначений» уже на клиенте соответственно.

 

Код этих функций:

 

// Функция преобразует ТаблицуЗначений в Массив из структур.
//
Функция ПреобразоватьТаблицуЗначенийВМассив(тзДанные) Экспорт

мсДанные = Новый Массив;

// Запишем в массив
Для Каждого СтрокаТЗ Из тзДанные Цикл

стСтрокаТаблицы = Новый Структура;
Для Каждого ИмяКолонки Из тзДанные.Колонки Цикл
стСтрокаТаблицы.Вставить(ИмяКолонки.Имя, СтрокаТЗ[ИмяКолонки.Имя]);
КонецЦикла;

мсДанные.Добавить(стСтрокаТаблицы);

КонецЦикла;

Возврат мсДанные;

КонецФункции // ПреобразоватьТаблицуЗначенийВМассив()

// Функция преобразует Массив из структур в ТаблицуЗначений.
//
Функция ПреобразоватьМассивВТаблицуЗначений(мсДанные) Экспорт

тзДанные = Новый ТаблицаЗначений;

Для Каждого ЭлементМассива Из мсДанные Цикл
// Рисуем колонки для таблицы
Если тзДанные.Колонки.Количество() = 0 Тогда
Для Каждого ЗначениеСтруктуры Из ЭлементМассива Цикл
тзДанные.Колонки.Добавить(ЗначениеСтруктуры.Ключ);
КонецЦикла;
КонецЕсли;

// Добавляем данные в таблицу
НоваяСтрока = тзДанные.Добавить();
Для Каждого ЗначениеСтруктуры Из ЭлементМассива Цикл
НоваяСтрока[ЗначениеСтруктуры.Ключ] = ЗначениеСтруктуры.Значение;
КонецЦикла;
КонецЦикла;

Возврат тзДанные;

КонецФункции // ПреобразоватьМассивВТаблицуЗначений()

35 Comments

  1. AlX0id

    ОбщегоНазначения.ТаблицаЗначенийВМассив(Таблица)

    не? )

    Reply
  2. KonstB

    1. Автор посмотри (0) — сравни. У тебя не оптимально.

    2. Функция ПреобразоватьМассивВТаблицуЗначений(мсДанные) — не будет работать в тонком клиенте

    Reply
  3. AnryMc
    Функция «ПреобразоватьТаблицуЗначенийВМассив» выполняется на сервере перед передачей данных, а «ПреобразоватьМассивВТаблицуЗначений» уже на клиенте соответственно.

    &НаСервереБезКонтекста

    &НаКлиентеБезКонтекста

    Reply
  4. Draconus

    (1) AlX0id, опять велосипед изобретаю))

    А в обратку кстати какой метод? «МассивВТаблицуЗначений» не нашел…

    Reply
  5. soap

    Попробовал можно воспользоваться, но при большой таблице чертовски медленно

    Reply
  6. gaglo

    А почему не ЗначениеВСтрокуВнутр ?

    Reply
  7. Draconus

    (6) gaglo, никто не говорил, что данный вариант — это универсальные методы, которые должны быть у каждого и пользоваться надо только ими)

    Это всего лишь один из возможных подходов к решению задач. Кстати как упоминалось в (5) далеко не самый оптимальный. Однако есть вероятность, что кто-то сочтет его полезным для себя.

    Reply
  8. AlX0id

    (4)

    А обратно лично я не нашел ) Пришлось писать )

    Reply
  9. Draconus

    (8) AlX0id, тогда половина кода не «велосипед» 🙂

    Reply
  10. Draconus

    (9) barankin, таблица значений с сервера не передается, а вот список значений передаваться должен.

    Хотя недавно у меня тоже не передавался, что странно, так как точно помню, что можно было… так же пришлось делать через массив.

    Reply
  11. Bukaska

    (4) Мутабельные значения — немножко другая тема..

    если у вас модуль серверный и не стоит галка вызов сервера и наоборот… то конечно будет эта тема..

    А так для тонкого клиента есть функционал: ДанныеФормыВЗначение и ЗначениеВДанныеФормы

    Об этом даже рассказывает Андрей Габец в тестовом доступе УЦ3 , отрывок из курса Оперативных задач

    Reply
  12. zarucheisky

    Передача массива структур с клиента на сервер в общем-то очевидна и давно известна.

    А вот подобный код в статье публиковать не стОит.

    Вложенные циклы по колонкам внутри перебора таблицы выглядят несколько неразумно.

    На самом деле, если конечно подумать, и посмотреть как ТЗ отображается в XML, то и решение придет как бы само 🙂

    Reply
  13. kg_am

    (6) gaglo,

    ЗначениеИзСтрокиВнутр() на тонком клиенте не работает.

    Reply
  14. peterxx

    Нормально работает, сам пользуюсь, правда преобразую ТЗ в структуру массивов. Массив тоже можно пинать между клиентом и сервером.

    Reply
  15. nixel

    Вот если бы кто написал функции по переводу тз в массив структур с двумя требованиями:

    1) обход данного массива так же как и ТЗ (есть)

    2) преобразование данного массива в ТЗ с сохранением типов колонок

    А то в крайних случаях приходится проходиться по колонке, смотреть все типы и строить ОписаниеТипов для конструктора ТЗ по собранным данным… Медленно и не всегда верно. Особенно если таблица пустая. Колонки потеряли, типы потеряли. Ну это так, мысли о высоком.

    Reply
  16. gaglo

    (7) — не ответ, а вот (14) — ответ. Спасибо.

    Reply
  17. Yashazz

    (13) Верно, хотя сериализация тоже не всякая прокатывает, особенно если в таблице разности и хитрости понапиханы. Да и городить огород иногда нерационально.

    Reply
  18. zarucheisky

    (18) Понапихай всего разного и посмотри как сериализуется

    Грубо говоря, сериализуется ВСЕГДА одинаково, как прописано в xsd-схеме ядра платформы.

    Reply
  19. wunderland

    скользкая тема, если в таблице есть значения Null — в этом случае в тонком клиенте и WEB-клиенте код отрабатывает по разному.

    Reply
  20. Yashazz

    (19) Некоторые вещи просто НЕ сериализуются. Иногда — противореча СП, например, «РазмерКартинки». А схему самой 1С я видел, так вот, теоретически должное иногда практически не выходит. Ну, xsd 1С — вообще отдельная история, здесь это оффтоп )))

    Reply
  21. realEvgenius

    А в чем соль, так сказать?

    Функция ПреобразоватьМассивВТаблицуЗначений(мсДанные)

    Всеравно передает ТЗ с сервера и всеравно вызывает ошибку…

    Или я деревянный или чушь какая-то

    Reply
  22. Draconus

    (22) realEvgenius

    Вариант 1.

    1. С помощью ПреобразоватьТаблицуЗначенийВМассив() делаем массив, который гоняем между клиентом и сервером.

    2. Обрабатываем его (это уже сами выбираете как)

    3. Передаете на клиент обратно МАССИВ, который затем преобразуете в Таблицу значений с помощью ПреобразоватьМассивВТаблицуЗначений().

    Вариант 1,5.

    1. Делаем массив с помощью ПреобразоватьТаблицуЗначенийВМассив()

    2. Получаем на сервере, преобразуем в Таблицу значений с помощью ПреобразоватьМассивВТаблицуЗначений()

    3. Работаем с Таблицей значений

    З.Ы. Мне надо было для второго варианта.

    Reply
  23. realEvgenius

    (23) Вопрос Как в процедуре, которая идет после &НаКлиенте Использовать Таб значений как её туда передать? Ответ — никак. ПреобразоватьМассивВТаблицуЗначений() Это на сервере запускать? Оно возвращает Таб значений (Возврат тзДанные), которую нельзя передать в мою процедуру, которая выполняется на клиенте. Ибо система ругается.

    Смысл этих обработок? Таб значений передать на клиента нельзя. Преобразовываем её в массив, передаем массив на клиента, предаем массив функции ПреобразоватьМассивВТаблицуЗначений(), которая по идее должна дать таб знач и получаем туже ошибку. Наверное, я — деревянный, что-то не понимаю

    Reply
  24. Draconus

    (24) realEvgenius

    Обе функции кладутся в общий модуль, где проставлены галочки «Клиент» и » Сервер», назовем его «ОбщегоНазначенияКлиентСервер»

    &НаКлиенте
    Процедура ЧтотоДелаю1()
    
    //Есть уже таблица надо ее подправить на сервере
    ЧтотоДелаюНаСервере1(ОбщегоНазначенияКлиентСервер.ПреобразоватьТаблицуЗначенийВМассив(<НашаБеднаяТаблица>));
    
    КонецПроцедуры
    
    &НаСервере
    Процедура ЧтотоДелаюНаСервере1(НашБедныйМассив)
    НашаБеднаяТаблица = ОбщегоНазначенияКлиентСервер.ПреобразоватьМассивВТаблицуЗначений(НашБедныйМассив).Скопировать();
    // Мучаем нашу бедную таблицу, что-то из нее берем, что-то добавляем
    
    // Если надо вернуть отбратно, то делаем не процедуру, а функцию и возвращаем
    // ОбщегоНазначенияКлиентСервер.ПреобразоватьТаблицуЗначенийВМассив(<НашаБеднаяПЕРЕДЕЛАННАЯТаблица>)
    
    КонецПроцедуры

    Показать

    Я не знаю что тут еще можно добавить

    Reply
  25. realEvgenius

    Аааа…. В общий модуль… А я ж в томже модуле мучаю…

    попробую

    Reply
  26. svad1

    (25) как у вас получилось?

    //Есть уже таблица надо ее подправить на сервере
    
    Если на клиенте написать
    тзДанные = Новый ТаблицаЗначений; 

    то сразу ошибка.

    Как таблица значений может быть на клиенте? Нечего передавать по сути, так как сразу возникает ошибка… Я так понял таблица значений не может существовать на клиенте

    Тип не определен (ТаблицаЗначений)

    тзДанные = Новый <<?>>ТаблицаЗначений; (Проверка: Тонкий клиент)

    Reply
  27. logos

    Вот ведь парадокс…. Тип таблица значений на клиенте не определен, а реквизит формы типа «таблица значений» возможен и работает. Сдается мне это вопрос религиозного характера!

    Reply
  28. nixel

    (28) logos, посмотрите отладчиком, какой тип у этого реквизита. Удивитесь.

    Reply
  29. It-developer

    Они ограничили передачи ТаблицыЗначений, потому что хз что туда можно напихать. Было бы лучше не ограничивать таблицу, а ограничивать типы передаваемых данных

    Reply
  30. AlexeyPapanov

    Коллеги, я сейчас решаю озвученную в теме задачу.

    Пишу обработку заполнения табличной части (с вызовом клиентского метода).

    Юзер указывает ссылку на документ, по которой я на сервере собираю ТЗ, а потом эту ТЗ возвращаю на клиент, чтобы заполнить ТЧ своего документа.

    Понимаю, что можно тупо упаковать строки в структуры,, а их в массив, и этот массив вернуть на клиент.

    но тут в (12) сказано

    А так для тонкого клиента есть функционал: ДанныеФормыВЗначение и ЗначениеВДанныеФормы

    это применимо в моей задаче или проще массив из структур швырнуть на клиент?

    Reply
  31. chukawata

    Спасибо. Помогло.

    Reply
  32. komanch75

    Можно передавать массив, элементы которого — массивы выгруженных колонок таблицы.

    Правда таблица значений доступна только на толстом клиенте.

    &НаКлиенте
    Процедура ЧтоТо(Команда)
    Мсс=ПередачаНаСервере();
    ТЗ=Новый ТаблицаЗначений;
    Для йй=0 по Мсс.Количество()-1 цикл
    ИмяКолонки=СокрЛП(Мсс[йй][0]);
    ТЗ.Колонки.Добавить(ИмяКолонки);
    Мсс[йй].Удалить(0);
    Если йй=0 тогда //на первом проходе добавим в ТЗ строки
    Для цц=1 по Мсс[йй].Количество() цикл
    ТЗ.Добавить();
    КонецЦикла;
    КонецЕсли;
    ТЗ.ЗагрузитьКолонку(Мсс[йй], ТЗ.Колонки[ИмяКолонки]);
    КонецЦикла;
    КонецПроцедуры
    
    &НаСервере
    Функция ПередачаНаСервере()
    ТЗ = КадровыйУчет.КадровыеДанныеСотрудников(Ложь, Объект.Сотрудник, ЗапрашиваемыеКадровыеДанные, ТекущаяДата()); //формирует ТЗ
    Мсс=Новый Массив;
    Для йй=0 по ТЗ.Колонки.Количество()-1 цикл
    кл=ТЗ.ВыгрузитьКолонку(ТЗ.Колонки[йй]);
    кл.Вставить(0, СокрЛП(ТЗ.Колонки[йй].Имя)); //первой строкой имя колонки
    Мсс.Вставить(йй,кл);
    КонецЦикла;
    Возврат Мсс;
    КонецФункции
    

    Показать

    Reply
  33. azhilichev

    (31) ДанныеФормыВЗначение и ЗначениеВДанныеФормы нельзя открывать от контекста формы. Бесконтекстные вызовы не отработают.

    Reply
  34. user659124_s.kostina

    (6) Пыталась сравнивать этой функций две тз, одна была выгружена из результата запроса, другая сформирована в цикле, и они НЕ были одинаковыми. Сравнила полученный текст, разница, как я поняла в индексах. А вот сравнив массивы, полученные из этих тз, я получила верный результат сравнения.

    Reply
  35. hobi

    Гораздо эффективнее будет работать так (нет двойных циклов и меньше объем данных при сериализации):

    Функция ТзВКоллекцию(ТЗ) Экспорт
    
    Коллекция = Новый Структура;
    Для каждого Колонка Из ТЗ.Колонки Цикл
    Коллекция.Вставить(Колонка.Имя, ТЗ.ВыгрузитьКолонку(Колонка.Имя));
    КонецЦикла;
    Возврат Коллекция;
    
    КонецФункции
    
    Функция КоллекцияВТЗ(Коллекция) Экспорт
    
    ТЗ = Новый ТаблицаЗначений;
    // добавим пустые строки
    Для каждого Эл Из Коллекция Цикл
    КоличествоСтрок = Эл.Значение.Количество();
    Для Индекс = 1 По КоличествоСтрок Цикл
    ТЗ.Добавить();
    КонецЦикла;
    Прервать;
    КонецЦикла;
    
    // загрузим колонки
    Для каждого Эл Из Коллекция Цикл
    ТЗ.Колонки.Добавить(Эл.Ключ);
    ТЗ.ЗагрузитьКолонку(Эл.Значение, Эл.Ключ);
    КонецЦикла;
    
    Возврат ТЗ;
    
    КонецФункции
    

    Показать

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *