Неограниченное количество строк в табличной части документа

06.04.23

Разработка - Механизмы платформы 1С

Как быть, если вам нужно загрузить в документ более 99999 строк? Существуют различные решения от пересмотра архитектуры конфигурации и разбивки документа на несколько более мелких, до помещения на форму документа таблицы значений и записи её содержимого в регистр сведений. В данной публикации я рассматриваю наиболее лаконичный и простой для понимания на мой взгляд вариант.

На днях возникла задача по загрузке файлов, содержащих сведения об оплате физическими лицами некой коммунальной услуги. Информацию предоставлял расчетный центр, ведущий учет начислений и платежей физических лиц в небольшом городе с населением чуть более 1 млн. жителей. Каждый файл в среднем содержал по 300 тысяч записей о поступивших оплатах по лицевым счетам физ.лиц. Условием заказчика было, что файл должен один-к-одному загружаться в документ 1С, чтобы пользователи видели однозначное соответствие между исходным файлом и результатом загрузки в виде документа 1С.

Задача вроде бы простая, если бы не один нюанс: как известно, табличная часть документа 1С может содержать максимум 99999 строк. Это ограничение во многом искусственное и призвано обеспечить соблюдение некоторых критериев производительности в типовых решениях. Для меня же оно означало, что либо придется отступить от требований заказчика и загружать исходные файлы с разбивкой по нескольким результирующим документам, либо искать нестандартное решение.

Сделав выбор в пользу второго варианта, я стал искать способ обойти ограничение, накладываемое платформой на максимальное количество записей в табличной части документа. Первое что стало очевидно, механизм ограничения применяется только в момент записи документа платформой в базу данных. То есть мы совершенно спокойно можем интерактивно или программно добавить в документ любое количество строк и никаких ограничений платформа на эти действия не накладывает. Проблема возникает лишь тогда, когда мы пытаемся записать созданный документ в БД. Платформа сигнализирует нам о проблеме следующим информационным сообщением. 

 

 

После чего транзакция записи документа прерывается. А что если на момент этой проверки мы временно переложим все данные из табличной части в какое-то иное хранилище, а уже после проверки снова вернем их в табличную часть. Давайте попробуем?

Для начала добавим в документ реквизит ХранилищеТабличнойЧастиДокумента, тип - хранилище значений.

Создаем в модуле формы документа серверную процедуру ПередЗаписьюНаСервере(), в которую добавляем следующий код:

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	ВремТЗ = ТекущийОбъект.ТабличнаяЧастьСписок.Выгрузить();
	ТекущийОбъект.ХранилищеТабличнойЧастиДокумента = Новый ХранилищеЗначения(ВремТЗ, Новый СжатиеДанных(9));
	ТекущийОбъект.ТабличнаяЧастьСписок.Очистить();
	
КонецПроцедуры

Смысл в том, чтобы выгрузить табличную часть в реквизит документа ХранилищеТабличнойЧастиДокумента и затем удалить все строки из неё. Таким образом на момент выполнения платформенной проверки на количество записей в табличной части - она у нас будет пустая.

Далее уже в модуле документа в процедуре ПриЗаписи() нам необходимо повторно прочитать состояние табличной части до её очистки.

Процедура ПриЗаписи(Отказ)
	
	ТабличнаяЧастьСписок.Загрузить(ХранилищеТабличнойЧастиДокумента.Получить());

КонецПроцедуры

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

Зачем мы это делаем? Да, записать в базу документ с восстановленной табличной частью уже не получится. Однако, нам в первую очередь нужно не это. Во-первых пользователь мог нажать просто на кнопку Записать без закрытия формы документа. И нам нужно обеспечить отображение данных в табличной части. Во-вторых, если вызов процедуры записи документа делается из формы списка, например, при выборе в контекстном меню команды Провести, нам нужно обеспечить передачу в процедуру ОбработкаПроведения() объекта, содержащего непустую табличную часть.

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

Хочу обратить ваше внимание, что в результате возникает очень странная и неочевидная для многих ситуация. В базу данных записан документ с пустой табличной частью, но его движения сформированы на основании объекта, в котором мы перед процедурой проведения восстановили содержимое ТЧ. Я не знаю, насколько такую ситуацию можно назвать багом платформы или недокументированной особенностью, но это работает на сегодняшний день именно так. На этом можно было бы и поставить точку. Все 300 тысяч строк мы загрузили в документ, провели его, и сформировали нужные нам движения. Но остался еще один момент... Что делать, если пользователь захочет открыть документ и отредактировать его? Ведь табличная часть после считывания документа из БД будет пустой! Как быть?

Элементарно. У нас же есть сохраненные в реквизите ХранилищеТабличнойЧастиДокумента данные. Так давайте при чтении содержимого документа на сервере вновь загрузим их в табличную часть. 

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

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)

	Объект.ТабличнаяЧастьСписок.Загрузить(ТекущийОбъект.ТабличнаяЧастьДокумента.Получить());
	
КонецПроцедуры

На этом всё!

Поделитесь, пожалуйста, вашим мнением: какие подводные камни и ограничения могут быть при эксплуатации такого решения? И какие альтернативные варианты записи объектов с табличной частью, содержащей большое количество записей, превышающие лимиты платформы 1С, используете вы?

См. также

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    4027    bayselonarrend    18    

142

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    4059    dsdred    16    

76

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    9574    YA_418728146    25    

70

Перенос данных 1C Механизмы платформы 1С Системный администратор Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    8856    dsdred    44    

123

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    21076    SeiOkami    46    

129

Механизмы платформы 1С Системный администратор Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    15212    human_new    27    

79

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    11548    YA_418728146    7    

154
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Жарков 06.04.23 12:41 Сейчас в теме
С ходу вижу следующие ограничения:
1. при проведении нельзя пользоваться стандартным подходом: получение данных для проведения запросом из базы. Обычно запрос берет табличную часть из базы для преобразования в таблицы движений, так быстрее. Тут надо в запрос передавать сохраненную таблицу, что несколько медленней.
2. в системах ERP отражение в регламентированном учете идет независимо от проведения, часто списком, без наличия объекта в памяти. Тогда это все надо вытаскивать из регистров оперативного учета, то есть не должно в табличной части оставаться то, чего нет в регистрах, но должно использоваться в проводках.
3. отчеты по табличной части документа не построишь.

Теперь пользовательская часть:
Отредактировал или просто человек документ - он модифицирован.
Человек нажал на кнопку "Записать"(но не "Записать и закрыть") - документ записался, но он по прежнему модифицирован.
При выходе из формы его опять спросят, надо ли сохранять документ.

Все это не помешает, если об этом просто не забывать.
Идея хорошая, но зачем тогда тут вообще табличная часть?
Редактируем сохраняемую таблицу прямо на форме и также сохраняем из данных формы. Проведение документа также берет данные просто из хранилища.
Alex17; 7OH; DrAku1a; ZOMI; +4 Ответить
2. s.sintsov 249 06.04.23 13:57 Сейчас в теме
(1) отвечу на ваш вопрос, зачем нужна табличная часть. Представим, что данный документ открыли на редактирование сразу два пользователя. Первый внес изменения и записал документ, второй пытается внести изменения. В случае с табличной частью он сразу при попытке редактирования табличной части получит сообщение о том, что документ был модифицирован и необходимо перечитать данные. В случае с таблицой значений на форме такого поведения не будет, и второй пользователь получит сообщение о проблеме только в момент попытки записи документа либо изменения каких-либо реквизитов основного объекта формы.
5. Жарков 06.04.23 20:30 Сейчас в теме
(2) А поставить на таблицу значений флаг "Сохраняемые данные" не пробовали?
По описанию попытка изменения реквизита формы с этим флагом должна приводить к блокировке, как и изменение реквизитов объекта.
DrAku1a; s.sintsov; +2 Ответить
3. s.sintsov 249 06.04.23 14:23 Сейчас в теме
(1)
Теперь пользовательская часть:
Отредактировал или просто человек документ - он модифицирован.
Человек нажал на кнопку "Записать"(но не "Записать и закрыть") - документ записался, но он по прежнему модифицирован.
При выходе из формы его опять спросят, надо ли сохранять документ.


Такую ситуацию не получается воспроизвести. После записи документа по кнопке Записать без закрытия формы флаг модифицированности в результате загрузки в процедуре ПриЗаписи табличной части объекта не устанавливается. Мне самому, кстати, интересно - почему. Попробую разобраться, но оно работает с точки зрения пользователя как раз как нужно - без лишних вопросов.
4. Жарков 06.04.23 18:45 Сейчас в теме
(3) Странно. Раньше любое изменение документа взводило модифицированность, даже если это проводилось из события "ПриЗаписи".
6. Dragonim 140 07.04.23 06:25 Сейчас в теме
Если документом управляете только вы и на производительность плевать, то можно сделать как описано в статье, в противном случае я бы побоялся. Сомневаюсь, что разработчик со стороны готов к ситуации, когда табличная часть пустая и необходимо ориентироваться только на движения документа.

Данная задача отлично решается через разбивку на несколько документов. Вот один из примеров такой разбивки: во время первой записи разбиваем табличную часть на порции и каждую записываем в свой документ (хранение зависимостей чисто технический момент). В дальнейшем работа производиться из спец. формы которая очень похожа на форму документа, но вместо табличных частей в ней динамические списки.

В результате:
1. Ни как не меняется логика конфигурации для стороннего разработчика
2. Можно оптимизировать чтение и запись

Разумеется можно навернуть много доп. плюшек, например, при открытии исходного документам открывается спец. форма (чтобы не портить пользовательский опыт), сделать поиск по динамическому списку (как будет работать поиск в большой табличной части я не знаю), вводить доп. обработки (обычно обработки не рассчитаны на такие большие табличные части) и прочее.
7. bulpi 216 07.04.23 08:11 Сейчас в теме
А мне понравилось. Решение красивое, в отличии от разбивки на несколько документов.
8. TSSV 1148 07.04.23 09:25 Сейчас в теме
Я в одном решении, когда тоже столкнулся с этой проблемой, вообще отказался от ТЧ в пользу РС, специфика задачи позволяла легко это сделать. Может вам тоже рассмотреть РС вместо ХранилищеТабличнойЧастиДокумента?
bakmistoff1977; NorraSaltolinen; kuzyara; mrChOP93; alex_bob; DrAku1a; +6 Ответить
9. roman72 384 07.04.23 11:54 Сейчас в теме
А что мешает сделать такой вариант - размещать эти гигантские количества строк таблиц в отдельном регистре/хранилище,
а документ связывать с блоком записей через индекс/ключ/имя/ссылку документа?
При открытии документа по ссылке, эти выборки будут вызываться в таблицу /закладку документа (по вызову пользователя) и то лучше по нажатию кнопки пользователем - не при каждом открытии это ему нужно.
Если документ или дальше по бизнес-процессу другой объект 1С обрабатывает эту таблицу, то проводиться может результирующий запрос или множество таких запросов (то есть по сути ОЛАП_кубы).
10. TMV 14 08.04.23 16:20 Сейчас в теме
Кто-нибудь задумывался, почему в платформе заложено такое ограничение?
23. PlatonStepan 38 24.04.23 08:33 Сейчас в теме
(10)
В ТЧ может быть много колонок. Каждая колонка может хранить значение большого объёма.
При чтении/изменении объекта читаются/переписываются все записи ТЧ.
Таким образом всего лишь обращением к одному объекту можно вычерпать все ресурсы клиента и сервера.

Ограничение искусственное, просто дурацкая защита от дурака, по сути.
11. paramedic 10.04.23 09:27 Сейчас в теме
Чисто в качестве упражнения ума можно, но с практической точки зрения применения не вижу. Типовые с трудом ворочают документы с 30 тысячами строк, а некоторые документы просто намертво вешаются от такого количества. Вы сами-то пробовали работать с таблицей формы в которой хотя бы 50 тысяч строк?
Кроме этого, работать с 300 тысячами строк - задача не для человека. Не может он интерактивно адекватно воспринять такой объем информации.
12. Бубузяка 62 10.04.23 10:34 Сейчас в теме
Есть решения на infostarte с применением регистра сведений. Измерение - документ, ресурсы - реквизиты таб. части. При записи все пишем в регистр, при чтении все из него читаем. Понятно, что динамическое считывание тут не работает, все сразу летит в форму.
Что касается дикого количества строк, то такое, к сожалению, встречается в бюджетировании, когда документ фиксируется бюджет на 12 мес. в разрезе статей и аналитик.
13. Wi5hMaCTeP 5 11.04.23 08:41 Сейчас в теме
Такой документ будет открываться минут 5, в зависимости от количества колонок. А записываться еще дольше. Прям вижу счастливого пользователя такого документа ;)
Только РС и динамический список.
15. Rasylit 14.04.23 13:58 Сейчас в теме
(13)
Только РС и динамический список.


Динамический список на УФ не позволяет редактировать строку сразу в списке, только отдельная форма.
Или это можно побороть штатно ?
16. Wi5hMaCTeP 5 14.04.23 18:08 Сейчас в теме
(15)
Можно редактировать, но не очень удобно.
Лучше небольшую форму записи сделать.
17. s.sintsov 249 17.04.23 15:17 Сейчас в теме
(13) Попробуйте, возможно, вас удивит время открытия. Если не хотите тратить своё время, мои замеры таковы: документ порядка 300 тысяч строк открывается 11 секунд. Для наших пользователей это приемлемо.
14. 7OH 70 11.04.23 12:39 Сейчас в теме
А что делать при изменении ссылок ? Вы же потом ТЧ не загрузите или получите кучу сломаных объектов.
--
Делал у себя на двух регистрах сведений.
Именно хранил сразу в регистре (в одном текущие данные, во втором после закрытия).
И работало шустро и наглядно и целостность данных была.
18. Alxby 1105 18.04.23 16:12 Сейчас в теме
Лучше делать РС, и подгрузку данных из него для просмотра на форме производить порциями. Но здесь может быть проблема - наличие повторяющихся строк в ТЧ допустимо, а в РС - нет, при их наличии в РС надо добавлять уникальный ключ.
25. oldy 3 25.02.24 16:30 Сейчас в теме
(18) так номер строки же. Пара регистратор-номер строки обеспечит уникальность ключа.
26. Alxby 1105 25.02.24 18:31 Сейчас в теме
(25)Не забудьте только про изменение номеров строк при вставке, удалении, сортировке
27. oldy 3 25.02.24 23:41 Сейчас в теме
(26)
Надо просто перед записью документа удалять весь регистр с отбором по регистратору и заново создавать
19. Alxby 1105 18.04.23 16:19 Сейчас в теме
Сохраненные в ХранилищеТабличнойЧастиДокумента строки недоступны для запросов, данные в нем не будут проверяться при поиске ссылок, т.е. некие объекты могут быть удалены, а в ХранилищеТабличнойЧастиДокумента останутся битые ссылки.
24. oldy 3 25.02.24 16:28 Сейчас в теме
(19) Поражен тем, что никто, кроме вас, про это ничего не сказал. К слову, эта проблема касается любых данных ссылочного типа, которые разработчик по каким-то причинам решил сохранять в хранилище. Ссылочная целостность при этом не поддерживается. А то, что нельзя использовать запросы для получения данных табличных частей - это вообще шляпа. Поэтому единственный корректный способ - сохранение в регистре сведений, зависимом от регистратора, который будет эмулировать табличную часть.
Автору спасибо за проведенное исследование.
20. dka80 21 19.04.23 14:14 Сейчас в теме
Сделать аналогично документу Операция из Бухгалтерии и хранить прямо в регистре
21. hasr 19.04.23 16:09 Сейчас в теме
Документ "Закрытие года", БГУ 2. В табличную часть подбирается больше 100 000 строчек. В конце таблицы куча строк с номером "99 999". Не давал себя записать с известной ошибкой. При этом в сам документ никто никогда не смотрит, строки ТЧ не редактируются, а только перезаполняются все разом. Предложенный метод решил проблему полностью. 10 строк кода - и все довольны. Спасибо автору!
22. RocKeR_13 1345 21.04.23 17:19 Сейчас в теме
Интересно стало, что вы там такое интересное проводите на 100 000+ строк?)
28. remix950 9 10.07.24 06:21 Сейчас в теме
Документ "Инвентаризация имущества казны" БГУ 2.0.98.26 подбирал более 148000 строк, в табличной части Инвентаризация и Остатки.
Используемый метод помог решить проблему!
Оставьте свое сообщение