Каждый начинающий разработчик или специалист из смежной сферы IT, впервые столкнувшись с платформой 1С:Предприятие, неизбежно наталкивается на жесткие архитектурные правила этой системы. Одними из самых частых «граблей» являются непонимание клиент-серверного взаимодействия и попытки прочитать данные напрямую из закрытого файла резервной копии (.dt). В этой статье мы подробно разберем, почему возникает популярная ошибка «Процедура или функция с указанным именем не определена», как устроена работа с контекстом в 1С, и покажем правильные, надежные способы выгрузки любых таблиц базы данных в текстовый формат или XML.
Прежде чем писать программный код, давайте проанализируем исходные данные. Очень часто руководство ставит задачу в духе: «Вот тебе файл резервной копии, выгрузи оттуда таблицы». Начинающий специалист пытается открыть этот файл сторонними утилитами или написать к нему прямой SQL-запрос. Это в корне неверный путь.
Выясним причину: файл с расширением .dt — это не база данных. Это специализированный сжатый архив (дамп), созданный платформой 1С. Внутри него данные упакованы в проприетарный формат. Ни одна внешняя утилита, включая популярную программу Tool1CD, не умеет читать данные напрямую из архива .dt.
Рассмотрим правильный алгоритм действий по шагам:
1Cv8.1CD..dt.Только после выполнения этих шагов архив распакуется, физические таблицы развернутся в полноценную базу данных формата .1CD (или загрузятся на SQL-сервер), и мы сможем приступить к работе с ними.
Попытка автора темы решить задачу «в лоб» привела к тому, что он открыл Модуль управляемого приложения, нашел предопределенный обработчик ПриНачалеРаботыСистемы и попытался вызвать оттуда свою функцию выгрузки. Давайте разберем, почему система выдала ошибку.
В платформе 1С реализовано строгое разделение контекста выполнения кода на клиент и сервер. Клиентское приложение (тонкий клиент, веб-клиент) отвечает за отображение интерфейса и взаимодействие с пользователем. На стороне клиента категорически запрещены любые прямые обращения к базе данных — это правило безопасности и производительности. Серверный контекст имеет полный доступ к СУБД, может выполнять запросы и обрабатывать тяжелые массивы данных.
Когда автор написал серверную функцию (например, с директивой &НаСервере) внутри Модуля управляемого приложения, он нарушил правила компиляции. Модуль управляемого приложения компилируется исключительно на клиенте. Размещать в нем директиву компиляции &НаСервере синтаксически запрещено. Платформа просто игнорирует эту директиву, компилятор не видит данную функцию в клиентском контексте и выдает ошибку: «Процедура или функция с указанным именем не определена».
Рассмотрим подробнее два надежных способа вызова серверного кода для решения нашей задачи.
Если вам обязательно нужно запустить выгрузку именно в момент старта системы, необходимо вынести логику в общий модуль:
УтилитыВыгрузкиСервер.Экспорт:
Процедура ВыполнитьЭкспортДанных() Экспорт
// Здесь располагается серверный код запроса к базе данных
КонецПроцедуры
Теперь из Модуля управляемого приложения (в событии ПриНачалеРаботыСистемы) вы сможете успешно вызвать эту процедуру:
Процедура ПриНачалеРаботыСистемы()
УтилитыВыгрузкиСервер.ВыполнитьЭкспортДанных();
КонецПроцедуры
Для выполнения разовых технических задач, таких как экспорт таблиц, крайне не рекомендуется вносить изменения в саму конфигурацию (это снимает базу с поддержки и усложняет будущие обновления). Намного проще и быстрее создать Внешнюю обработку.
Посмотрим на преимущества этого подхода:
Чтобы создать внешнюю обработку, в Конфигураторе выберите Файл -> Новый -> Внешняя обработка. На вкладке «Формы» добавьте форму обработки, разместите на ней кнопку и в модуле формы напишите код вызова серверной процедуры.
Автор темы столкнулся со следующей проблемой: при прямой выгрузке данных в некоторых полях вместо привычных текстовых названий (например, наименований номенклатуры или контрагентов) выгрузились длинные буквенно-цифровые строки в фигурных скобках вида {sadqwsdf-gdsgfwerewfsd-fggh-fjhj}.
Проанализируем ситуацию. В базах данных 1С все ссылочные типы данных (справочники, документы, перечисления) физически хранятся в таблицах СУБД в виде 128-битных уникальных идентификаторов — UUID (они же GUID). Текстовое представление (например, строка «Агуша») хранится в одной таблице, а в другой таблице (например, в регистре сведений) хранится лишь ссылка на эту запись в виде GUID.
Если вы делаете прямой запрос и пытаетесь неявно сложить ссылку со строкой, платформа возвращает внутренний идентификатор ссылки. Чтобы исправить это и получить понятный текст, используйте специальную функцию языка запросов 1С: ПРЕДСТАВЛЕНИЕ(ИмяПоля). Она автоматически преобразует ссылку в текстовое наименование объекта на уровне СУБД.
В сообщении №27 автор привел свой вариант работающего кода. Несмотря на то что у автора программа отработала, представленный код содержит серьезные ошибки, которые в реальной базе приведут к аварийному завершению работы системы.
Проанализируем эти ошибки:
query_result = query.Выполнить.Выгрузить; написана некорректно. В языке 1С вызовы методов объекта обязательно требуют наличия круглых скобок, даже если у них нет параметров. Правильная запись выглядит так: РезультатЗапроса = Запрос.Выполнить().Выгрузить();. Без скобок код выдаст ошибку компиляции.temp_row_str = temp_row_str + temp_cell; гарантированно вызовет критическую ошибку «Несоответствие типов», как только в ячейке таблицы окажется число, дата, булево значение или значение NULL (которое очень часто встречается в реальных базах при соединении таблиц). В 1С нельзя складывать строку с другими типами данных без явного преобразования. Необходимо использовать встроенную функцию Строка().file_stream = Новый ЗаписьТекста("d:\query_result.txt"); жестко прописывает путь к локальному диску D:\. Если база данных работает в клиент-серверном режиме (на SQL-сервере), этот код будет выполняться на стороне сервера приложений. Программа попытается создать файл на физическом диске серверного компьютера. Если у сервера нет диска D или у системной службы 1С нет прав на запись в корень этого диска, программа завершится аварийно с ошибкой доступа.С учетом всех разобранных ошибок, давайте составим правильный и надежный шаблон кода для выгрузки таблицы 1С в текстовый файл с разделителями-табуляциями. Этот код можно безопасно разместить в модуле управляемой формы нашей внешней обработки.
Разберем по шагам создание процедуры на сервере:
&НаСервере
Процедура ВыполнитьВыгрузкуНаСервере(ИмяПутиКФайлу)
// 1. Инициализируем запрос с получением строковых представлений полей
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДанныеКомпании.Период КАК Период,
| ПРЕДСТАВЛЕНИЕ(ДанныеКомпании.Организация) КАК ОрганизацияПредеставление,
| ДанныеКомпании.ИНН КАК ИНН,
| ДанныеКомпании.КПП КАК КПП
|ИЗ
| РегистрСведений.Данные_Компании КАК ДанныеКомпании";
// Выполняем запрос и выгружаем результат в таблицу значений
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
КоличествоКолонок = ТаблицаРезультата.Колонки.Количество();
// 2. Безопасно открываем файл для записи.
// На сервере лучше использовать временные каталоги во избежание проблем с правами доступа.
ЗаписьТекста = Новый ЗаписьТекста(ИмяПутиКФайлу, КодировкаТекста.UTF8);
// 3. Обходим строки таблицы результатов
Для Каждого СтрокаТаблицы Из ТаблицаРезультата Цикл
СтрокаДляЗаписи = "";
Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
ТекущееЗначение = СтрокаТаблицы[ИндексКолонки];
// Защищаем код от падения по ошибке "Несоответствие типов"
ТекстовоеЗначение = Строка(ТекущееЗначение);
СтрокаДляЗаписи = СтрокаДляЗаписи + ТекстовоеЗначение;
// Добавляем разделитель колонок (табуляцию), если это не последняя колонка
Если ИндексКолонки < КоличествоКолонок - 1 Тогда
СтрокаДляЗаписи = СтрокаДляЗаписи + Символы.Таб;
КонецЕсли;
КонецЦикла;
// Записываем сформированную строку в файл
ЗаписьТекста.ЗаписатьСтроку(СтрокаДляЗаписи);
КонецЦикла;
// Обязательно закрываем поток записи файла
ЗаписьТекста.Закрыть();
КонецПроцедуры
Для того чтобы данный код успешно работал в клиент-серверном режиме работы базы данных, путь к файлу должен формироваться на стороне клиента (например, через стандартный диалог выбора файла), после чего передаваться параметром на сервер. Это гарантирует, что файл запишется именно туда, куда ожидает пользователь.
Если перед вами стоит задача выгрузить абсолютно все таблицы информационной базы, а писать программный код под сотни метаданных вручную нет времени, можно воспользоваться мощной консольной функцией утилиты Tool1CD.
Утилита поддерживает работу через командную строку (CLI), что позволяет автоматизировать экспорт всей базы данных в формат XML одной командой.
Посмотрим на пример использования консольной команды:
Tool1CD.exe -eax "C:\FolderForExport" "C:\My1CBaseFolder\1Cv8.1CD"
Разберем параметры этой команды:
-eax расшифровывается как «Export All to XML» (Экспортировать всё в XML). Он указывает программе, что необходимо обойти абсолютно все физические таблицы базы данных."C:\FolderForExport" — каталог на вашем компьютере, куда утилита сохранит отдельные XML-файлы по каждой таблице базы данных."C:\My1CBaseFolder\1Cv8.1CD" — абсолютный путь к физическому файлу вашей файловой базы данных 1С.Данный способ работает мгновенно, не требует запуска платформы 1С и написания программного кода, что делает его идеальным инструментом для системных администраторов и сторонних разработчиков при решении экстренных задач интеграции.