Как в 1С 7.7 изменить тип колонки ТаблицыЗначений на составной тип или тип документов разного вида?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При активной разработке в среде 1С:Предприятие 7.7 с применением компоненты 1С++ разработчики часто сталкиваются с ситуацией, когда результат прямого SQL-запроса выгружается в стандартную ТаблицаЗначений. Если в тексте запроса колонка была жестко типизирована под конкретный документ (например, [Док $Документ.ПоступлениеТоваров]), ячейки таблицы принимают строгий ссылочный тип. При попытке программно добавить в эту же колонку строку с другим видом документа (например, Реализация) платформа 1С 7.7 блокирует операцию: значение либо сбрасывается в пустое, либо возникает ошибка несовпадения типов.

Разберем по шагам причины такого поведения платформы и подробно рассмотрим несколько практических способов решения этой задачи.

Причина ограничения типизации в 1С 7.7

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

Когда компонента 1С++ выполняет парсинг текста запроса и встречает конструкцию $Документ.ПоступлениеТоваров, она вызывает встроенные механизмы типизации колонок создаваемой таблицы. В результате на уровне ядра платформы устанавливается жесткий фильтр. Любая попытка присвоить ячейке ссылку другого типа игнорируется или приводит к ошибке. Чтобы обойти это поведение, необходимо либо изменить правила типизации на лету, либо скорректировать сам SQL-запрос, либо применить альтернативные структуры данных.

Способ 1. Изменение или снятие типизации колонки методами платформы

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

Для этого воспользуемся штатным методом УстановитьПараметрыКолонки(). У нас есть два пути настройки:

  1. Полное снятие типизации. Если передать в качестве типа пустую строку, колонка станет универсальной и сможет принимать любые значения (любые документы, справочники, строки или числа):
    
    // Снимаем ограничение типов с колонки
    ТЗ.УстановитьПараметрыКолонки("Док", "");
    
  2. Установка общего составного ссылочного типа «Документ». Если требуется разрешить любые виды документов, но защитить колонку от случайной записи строк или чисел, укажем базовый тип без конкретизации вида:
    
    // Разрешаем документы любого вида
    ТЗ.УстановитьПараметрыКолонки("Док", "Документ");
    

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

Способ 2. Корректная типизация общего типа $Документ в запросе 1С++

Если мы формируем прямой SQL-запрос через объект RainbowCommand или Query компоненты 1С++, правильнее всего сразу типизировать результирующую колонку как документ неопределенного вида. Посмотрим на детали реализации этого механизма.

Для создания ссылки на документ неопределенного вида ядру 1С требуются два поля: идентификатор документа (девятизначный IDDOC) и идентификатор его вида (числовой IDDOCDEF). Парсер 1С++ использует соглашение об именовании сопутствующих колонок: если основная колонка называется Док, парсер автоматически ищет поле с суффиксом _вид (т. е. Док_вид) или _kind.

Рассмотрим пример правильного построения выборки из таблицы журнала _1SJOURN:


ТекстЗапроса = "
|SELECT
|    Журнал.IDDocDef AS [Док_вид $ВидДок],
|    Журнал.IDDOC AS [Док $Документ]
|FROM
|    _1SJOURN AS Журнал
|WHERE
|    Журнал.Date_Time_IDDoc BETWEEN :НачДата AND :КонДата~
|";
ТЗ = рс.ВыполнитьИнструкцию(ТекстЗапроса);

Обратим внимание на следующие правила типизатора:

  1. Колонка Док_вид связывается с полем IDDocDef таблицы журнала. Типизация $ВидДок помогает явно указать парсеру назначение поля, хотя часто достаточно просто выбрать числовой идентификатор.
  2. Основная колонка Док типизируется метатипом $Документ (без точки и конкретного вида). При выгрузке в ТаблицаЗначений колонка автоматически получит общий тип Документ, что позволит без дополнительных манипуляций добавлять в нее накладные, счета, поступления или реализации.
  3. Если в базе идентификатор уже хранится в виде 13-значной строки (4 символа вида в 36-ричной системе счисления + 9 символов IDDOC, как в реквизитах неопределенного типа), поле можно типизировать как [Поле $Документ] без использования вспомогательной колонки _вид.

Способ 3. Выгрузка результата в ИндексированнуюТаблицу (ИТЗ)

Разберем еще один эффективный путь, принятый в среде разработчиков 1С++. Вместо стандартной платформенной ТаблицаЗначений результат выполнения инструкции можно направлять в объект ИндексированнаяТаблица (ИТЗ).

Объект ИндексированнаяТаблица реализован внутри внешней компоненты 1С++. Он работает с оперативной памятью напрямую и не накладывает жестких платформенных ограничений 1С 7.7 на типизацию данных внутри ячеек одной колонки. Даже если колонка была типизирована определенным образом, в ИТЗ можно свободно помещать значения других видов и типов данных.

Посмотрим на пример выгрузки напрямую в ИТЗ:


ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
рс.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ);

// Теперь в эту же колонку можно беспрепятственно добавлять любые документы:
ИТЗ.НоваяСтрока();
ИТЗ.Док = ДокументРеализация.ТекущийДокумент();

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

← На главную