В платформе «1С:Предприятие 7.7» на уровне ядра заложено жесткое архитектурное ограничение: любой документ может содержать только одну физическую табличную часть (ТЧ). Однако в реальной практике автоматизации учета — например, при оформлении выдачи спецодежды и одновременного расчета компенсации за неизрасходованные нормы — бизнес-логика требует наличия двух и более независимых таблиц на форме одного документа.
В рамках этой статьи мы детально проанализируем ситуацию, разберем причины возникновения этой проблемы и пошагово рассмотрим лучшие технические решения, выработанные ведущими разработчиками за годы существования платформы 1С 7.7. Мы изучим как простые способы визуального разделения, так и сложные архитектурные подходы с использованием подчиненных объектов и сериализации данных.
Рассмотрим классический пример из практики. В организации ведется учет выдачи вещей и спецодежды сотрудникам. При увольнении или плановом списании сотруднику необходимо оформить один документ, в котором:
Если пытаться уместить все эти разнородные данные в одну стандартную табличную часть 1С 7.7, форма станет перегруженной, а логика проведения и расчета — чрезвычайно запутанной. Выясним, какие существуют способы решения этой задачи.
Этот способ является наиболее простым в реализации и не требует создания дополнительных объектов в метаданных конфигурации. Вся информация продолжает физически храниться в единственной штатной табличной части документа, но для пользователя она выглядит как две совершенно разные таблицы на разных вкладках.
Рассмотрим по шагам алгоритм реализации этого метода:
НомТЧ (тип: Число, длина: 1). Этот реквизит будет служить маркером: значение "1" будет соответствовать строкам первой вкладки («Выдача»), значение "2" — строкам второй вкладки («Компенсация»).Посмотрим на пример реализации переключения закладок в модуле формы документа. Для этого используется предопределенная процедура ПриВыбореЗакладки:
Процедура ПриВыбореЗакладки(НомерЗакладки, ЗначениеЗакладки)
// Управляем видимостью колонок в зависимости от выбранной вкладки
Если ЗначениеЗакладки = "Выдача" Тогда
Форма.Цена.Видимость(0);
Форма.Сумма.Видимость(0);
Форма.ДокументВыдачи.Видимость(1);
ИначеЕсли ЗначениеЗакладки = "Компенсация" Тогда
Форма.Цена.Видимость(1);
Форма.Сумма.Видимость(1);
Форма.ДокументВыдачи.Видимость(0);
КонецЕсли;
// Активизируем фильтрацию строк на форме
// Применяем отбор строк по значению реквизита НомТЧ
УстановитьФильтрСтрок(ЗначениеЗакладки);
КонецПроцедуры
Основной минус данного подхода заключается в том, что стандартный механизм фильтрации строк табличной части в 1С 7.7 (через встроенный метод ВидыОтбора или визуальные хаки) работает нестабильно и имеет ограничения по производительности на больших объемах данных. Поэтому разработчики часто модернизируют этот метод с использованием виртуальной Таблицы Значений (ТЗ).
Это более продвинутый и профессиональный вариант первого метода. Вместо прямой работы со строками реальной ТЧ документа на форму выводятся независимые элементы диалога типа «ТаблицаЗначений» (например, ТЗ_Выдача и ТЗ_Компенсация).
Проанализируем детально схему работы этой технологии:
ПриОткрытии) мы считываем данные из единственной реальной ТЧ документа.ТаблицаЗначений в соответствии со значением реквизита-маркера НомТЧ.ПриЗаписи) мы полностью очищаем реальную табличную часть документа и программно «сливаем» данные из обеих экранных таблиц обратно в ТЧ, устанавливая для каждой строки соответствующий индекс НомТЧ.Разберем пример программного кода для реализации этого механизма. Сначала напишем процедуру инициализации и заполнения экранных таблиц при открытии формы:
Процедура ПриОткрытии()
// Создаем колонки для первой таблицы значений
ТЗ_Выдача.НоваяКолонка("Номенклатура", "Справочник.Номенклатура");
ТЗ_Выдача.НоваяКолонка("Количество", "Число", 10, 2);
ТЗ_Выдача.НоваяКолонка("ДатаВыдачи", "Дата");
// Создаем колонки для второй таблицы значений
ТЗ_Компенсация.НоваяКолонка("Номенклатура", "Справочник.Номенклатура");
ТЗ_Компенсация.НоваяКолонка("Количество", "Число", 10, 2);
ТЗ_Компенсация.НоваяКолонка("Цена", "Число", 15, 2);
ТЗ_Компенсация.НоваяКолонка("Сумма", "Число", 15, 2);
// Выгружаем данные из физической ТЧ документа в экранные ТЗ
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
Если НомТЧ = 1 Тогда
ТЗ_Выдача.НоваяСтрока();
ТЗ_Выдача.Номенклатура = Номенклатура;
ТЗ_Выдача.Количество = Количество;
ТЗ_Выдача.ДатаВыдачи = ДатаВыдачи;
ИначеЕсли НомТЧ = 2 Тогда
ТЗ_Компенсация.НоваяСтрока();
ТЗ_Компенсация.Номенклатура = Номенклатура;
ТЗ_Компенсация.Количество = Количество;
ТЗ_Компенсация.Цена = Цена;
ТЗ_Компенсация.Сумма = Сумма;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Теперь рассмотрим процедуру свертки и обратной записи данных при сохранении документа пользователем:
Процедура ПриЗаписи()
// Очищаем физическую табличную часть документа перед перезаписью
УдалитьСтроки();
// Переносим строки из первой таблицы (Выдача)
ТЗ_Выдача.ВыбратьСтроки();
Пока ТЗ_Выдача.ПолучитьСтроку() = 1 Цикл
НоваяСтрока();
НомТЧ = 1;
Номенклатура = ТЗ_Выдача.Номенклатура;
Количество = ТЗ_Выдача.Количество;
ДатаВыдачи = ТЗ_Выдача.ДатаВыдачи;
КонецЦикла;
// Переносим строки из второй таблицы (Компенсация)
ТЗ_Компенсация.ВыбратьСтроки();
Пока ТЗ_Компенсация.ПолучитьСтроку() = 1 Цикл
НоваяСтрока();
НомТЧ = 2;
Номенклатура = ТЗ_Компенсация.Номенклатура;
Количество = ТЗ_Компенсация.Количество;
Цена = ТЗ_Компенсация.Цена;
Сумма = ТЗ_Компенсация.Сумма;
КонецЦикла;
КонецПроцедуры
Преимущества метода виртуальных ТЗ:
Недостатки метода:
Один из самых надежных и элегантных способов с точки зрения сохранения ссылочной целостности базы данных и высокой производительности. Его суть заключается в вынесении данных второй табличной части за рамки самого документа.
Для реализации этого метода выполним следующие шаги:
СоставКомпенсацииДокумента. В качестве его владельца указываем тип Документ.СписаниеИВыдачаВещей.Номенклатура, Количество, Цена, Сумма).Посмотрим, как выглядит программная логика считывания данных из подчиненного справочника при открытии документа:
Процедура ЗагрузитьДанныеИзСправочника()
ТЗ_Компенсация.УдалитьСтроки();
Спр = СоздатьОбъект("Справочник.СоставКомпенсацииДокумента");
// Устанавливаем отбор по владельцу - текущему документу
Спр.ИспользоватьВладельца(ТекущийДокумент());
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
ТЗ_Компенсация.НоваяСтрока();
ТЗ_Компенсация.Номенклатура = Спр.Номенклатура;
ТЗ_Компенсация.Количество = Спр.Количество;
ТЗ_Компенсация.Цена = Спр.Цена;
ТЗ_Компенсация.Сумма = Спр.Сумма;
// Сохраняем ссылку на элемент для последующей быстрой перезаписи
ТЗ_Компенсация.СсылкаНаЭлемент = Спр.ТекущийЭлемент();
КонецЦикла;
КонецПроцедуры
При записи документа мы синхронизируем изменения. Если строка в ТЗ новая — создаем элемент справочника, если изменена — обновляем существующий, если удалена — удаляем элемент справочника.
Почему этот метод считается одним из лучших?
1SENTRY или специализированные таблицы ТЧ документов SQL-версии не раздуваются лишними полями.Запрос, обращаясь напрямую к метаданным справочника.Этот метод часто используется как быстрое "обходное" решение (workaround), когда нет возможности или желания менять структуру метаданных конфигурации путем добавления новых таблиц или справочников.
Идея метода заключается в следующем: вся вторая табличная часть на форме верстается как обычная экранная «ТаблицаЗначений». Но хранится она в базе данных внутри одного-единственного текстового реквизита шапки документа с типом данных «Строка неограниченной длины».
Для реализации используются мощные встроенные функции платформы 1С 7.7: ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр(). Они позволяют преобразовывать сложные объекты платформы (включая таблицы значений со всеми строками, колонками, типами данных и ссылками) в одну системную строку специального формата и восстанавливать их обратно.
Разберем, как выглядит этот код на практике. Запись таблицы значений в текстовый реквизит шапки ХранилищеТЧ2 при сохранении документа:
Процедура ПриЗаписи()
// Сериализуем экранную таблицу компенсаций в системную строку
ХранилищеТЧ2 = ЗначениеВСтрокуВнутр(ТЗ_Компенсация);
КонецПроцедуры
И обратное чтение (десериализация) данных при открытии формы документа:
Процедура ПриОткрытии()
Если ПустаяСтрока(ХранилищеТЧ2) = 0 Тогда
// Восстанавливаем полноценную таблицу значений со всеми данными из строки
ТЗ_Компенсация = ЗначениеИзСтрокиВнутр(ХранилищеТЧ2);
Иначе
// Если документ новый и строка пуста - инициализируем структуру таблицы вручную
ТЗ_Компенсация.НоваяКолонка("Номенклатура", "Справочник.Номенклатура");
ТЗ_Компенсация.НоваяКолонка("Количество", "Число", 10, 2);
КонецЕсли;
КонецПроцедуры
Важные технологические риски при использовании сериализации:
<Объект не найден>.1SBLOB.dbf. При высокой интенсивности работы пользователей этот файл начинает лавинообразно увеличиваться в размерах, что нередко приводит к критическим сбоям СУБД, повреждению таблиц и зависанию транзакций.Этот сложный, но проверенный временем подход использовался самой фирмой «1С» в крупных тиражных решениях, таких как «Зарплата и Кадры 7.7» (для разделения сложных расчетов по отпускам и больничным листам).
Суть схемы состоит в следующем: в системе создаются два самостоятельных документа:
ВыдачаВещейСотруднику — основной документ с первой табличной частью.КомпенсацияВещейСотруднику — подчиненный документ со второй табличной частью.Для пользователя создается полная иллюзия работы в одном окне. На форме основного документа размещаются вкладки. При переходе на вторую вкладку система "под капотом" находит подчиненный документ (или создает его, если он еще не существует), считывает его ТЧ и отображает ее на форме основного документа в виде таблицы значений. При проведении или сохранении основного документа программно запускается запись и проведение подчиненного документа в рамках одной общей транзакции.
Чтобы подчиненные документы не путали операторов базы данных, их программно исключают из отображения во всех общих журналах документов конфигурации.
Для облегчения выбора оптимальной архитектуры под конкретные требования проекта проанализируем сравнительную таблицу преимуществ и недостатков каждого подхода:
| Критерий сравнения | Метод псевдо-ТЧ (Способ 1, 2) | Подчиненный справочник (Способ 3) | Сериализация в строку (Способ 4) | Подчиненный документ (Способ 5) |
|---|---|---|---|---|
| Сложность программного кода | Средняя | Средняя | Очень низкая (простая строка) | Высокая (синхронизация транзакций) |
| Ссылочная целостность БД | Да (полная штатная) | Да (полная штатная) | Нет (риск удаления объектов) | Да (полная штатная) |
| Возможность быстрых отчетов | Да (по общей ТЧ с фильтром) | Да (очень удобно по справочнику) | Нет (требуется парсинг строк) | Да (по регистрам подчиненного дока) |
| Влияние на размер базы данных | Минимальное | Минимальное | Высокое (раздувание 1SBLOB.dbf) | Среднее (создание новых объектов) |
Для бизнес-задачи интеграции учета выдачи вещей и компенсаций на платформе 1С 7.7 наиболее сбалансированным решением является Способ №3 (Использование подчиненного справочника) или Способ №2 (Виртуальные ТЗ на форме).
Они обеспечивают необходимую гибкость интерфейса, защищают базу данных от случайного удаления номенклатурных позиций пользователями и гарантируют высокую скорость работы системы даже при накоплении данных за несколько лет.