При активной разработке в среде 1С:Предприятие 7.7 с применением компоненты 1С++ разработчики часто сталкиваются с ситуацией, когда результат прямого SQL-запроса выгружается в стандартную ТаблицаЗначений. Если в тексте запроса колонка была жестко типизирована под конкретный документ (например, [Док $Документ.ПоступлениеТоваров]), ячейки таблицы принимают строгий ссылочный тип. При попытке программно добавить в эту же колонку строку с другим видом документа (например, Реализация) платформа 1С 7.7 блокирует операцию: значение либо сбрасывается в пустое, либо возникает ошибка несовпадения типов.
Разберем по шагам причины такого поведения платформы и подробно рассмотрим несколько практических способов решения этой задачи.
Выясним причину проблемы. В платформе 1С:Предприятие 7.7 колонка объекта ТаблицаЗначений может быть нетипизированной (принимать любые типы данных), типизированной общим базовым типом (например, Документ без указания вида) либо строго типизированной конкретным метаописанием (например, Документ.ПоступлениеТоваров).
Когда компонента 1С++ выполняет парсинг текста запроса и встречает конструкцию $Документ.ПоступлениеТоваров, она вызывает встроенные механизмы типизации колонок создаваемой таблицы. В результате на уровне ядра платформы устанавливается жесткий фильтр. Любая попытка присвоить ячейке ссылку другого типа игнорируется или приводит к ошибке. Чтобы обойти это поведение, необходимо либо изменить правила типизации на лету, либо скорректировать сам SQL-запрос, либо применить альтернативные структуры данных.
Проанализируем самый простой сценарий: запрос уже отработал, результат помещен в ТаблицаЗначений, и нам нужно снять строгое ограничение конкретного вида документа перед добавлением новых строк.
Для этого воспользуемся штатным методом УстановитьПараметрыКолонки(). У нас есть два пути настройки:
// Снимаем ограничение типов с колонки
ТЗ.УстановитьПараметрыКолонки("Док", "");
// Разрешаем документы любого вида
ТЗ.УстановитьПараметрыКолонки("Док", "Документ");
Важный нюанс: вызов метода УстановитьПараметрыКолонки() меняет правила валидации для последующих операций добавления и изменения строк, однако он не конвертирует и не разрушает данные, которые уже записаны в существующих строках таблицы.
Если мы формируем прямой SQL-запрос через объект RainbowCommand или Query компоненты 1С++, правильнее всего сразу типизировать результирующую колонку как документ неопределенного вида. Посмотрим на детали реализации этого механизма.
Для создания ссылки на документ неопределенного вида ядру 1С требуются два поля: идентификатор документа (девятизначный IDDOC) и идентификатор его вида (числовой IDDOCDEF). Парсер 1С++ использует соглашение об именовании сопутствующих колонок: если основная колонка называется Док, парсер автоматически ищет поле с суффиксом _вид (т. е. Док_вид) или _kind.
Рассмотрим пример правильного построения выборки из таблицы журнала _1SJOURN:
ТекстЗапроса = "
|SELECT
| Журнал.IDDocDef AS [Док_вид $ВидДок],
| Журнал.IDDOC AS [Док $Документ]
|FROM
| _1SJOURN AS Журнал
|WHERE
| Журнал.Date_Time_IDDoc BETWEEN :НачДата AND :КонДата~
|";
ТЗ = рс.ВыполнитьИнструкцию(ТекстЗапроса);
Обратим внимание на следующие правила типизатора:
Док_вид связывается с полем IDDocDef таблицы журнала. Типизация $ВидДок помогает явно указать парсеру назначение поля, хотя часто достаточно просто выбрать числовой идентификатор.Док типизируется метатипом $Документ (без точки и конкретного вида). При выгрузке в ТаблицаЗначений колонка автоматически получит общий тип Документ, что позволит без дополнительных манипуляций добавлять в нее накладные, счета, поступления или реализации.IDDOC, как в реквизитах неопределенного типа), поле можно типизировать как [Поле $Документ] без использования вспомогательной колонки _вид.Разберем еще один эффективный путь, принятый в среде разработчиков 1С++. Вместо стандартной платформенной ТаблицаЗначений результат выполнения инструкции можно направлять в объект ИндексированнаяТаблица (ИТЗ).
Объект ИндексированнаяТаблица реализован внутри внешней компоненты 1С++. Он работает с оперативной памятью напрямую и не накладывает жестких платформенных ограничений 1С 7.7 на типизацию данных внутри ячеек одной колонки. Даже если колонка была типизирована определенным образом, в ИТЗ можно свободно помещать значения других видов и типов данных.
Посмотрим на пример выгрузки напрямую в ИТЗ:
ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
рс.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ);
// Теперь в эту же колонку можно беспрепятственно добавлять любые документы:
ИТЗ.НоваяСтрока();
ИТЗ.Док = ДокументРеализация.ТекущийДокумент();
Использование ИТЗ не только решает вопрос с гетерогенными данными в колонках, но и существенно ускоряет сортировку, поиск и группировку больших объемов информации по сравнению со штатной ТаблицаЗначений.