При разработке отчетов и механизмов интеграции в среде 1С:Предприятия 7.7 с использованием внешней компоненты 1С++ нередко возникает задача получить данные из другой информационной базы. При этом разработчики стремятся сохранить удобство использования метапарсера, чтобы писать запросы с конструкциями вида $Справочник.Контрагенты или $Документ.Поставка, не выясняя вручную идентификаторы таблиц и полей в чужой структуре данных.
В этой статье мы подробно рассмотрим, как правильно подключиться к сторонней базе данных (SQL или файловой), подключить её файл метаданных (1Cv7.md) к парсеру и избежать распространенных ошибок авторизации.
Самый простой и эффективный способ работы с удаленной базой данных — использование метода ПрисоединитьИБ объекта ODBCDatabase. Этот метод считывает файл параметров базы 1Cv7.dba и структуру метаданных 1Cv7.md из указанного каталога, настраивая метапарсер ODBCRecordSet на работу со схемой удаленной базы.
Разберем по шагам правильную последовательность вызовов:
ODBCDatabase.Соединение().ПрисоединитьИБ(), передавая путь к каталогу удаленной информационной базы.ODBCRecordSet с помощью метода УстБД().Посмотрим на рабочий пример кода функции для выгрузки данных из складской базы:
Функция ПолучитьДанныеСклада(НачДата)
Перем Результат;
Результат = СоздатьОбъект("ТаблицаЗначений");
Результат.НоваяКолонка("УИД", "Строка", 9);
Результат.НоваяКолонка("Документ_дата", "Дата");
Каталог1С = "\\ServerName\base\sklad\";
СерверSQL = "SQL-SERVER-01";
БазаSQL = "sklad2014";
userSQL = "sa";
pwdSQL = "SecretPass123";
БазаПодкл = СоздатьОбъект("ODBCDatabase");
СтрокаСоединения = "DRIVER=SQL Server;SERVER=" + СокрЛП(СерверSQL) + ";UID=" + СокрЛП(userSQL) + ";PWD=" + СокрЛП(pwdSQL) + ";DATABASE=" + СокрЛП(БазаSQL) + ";";
Если БазаПодкл.Соединение(СтрокаСоединения) = 0 Тогда
Сообщить("Не удалось подключиться к базе " + БазаSQL + " - проверьте параметры подключения!");
Возврат Результат;
КонецЕсли;
// Присоединяем каталог базы для инициализации метапарсера
БазаПодкл.ПрисоединитьИБ(Каталог1С);
ЗапросСклад = СоздатьОбъект("ODBCRecordSet");
ЗапросСклад.УстБД(БазаПодкл);
ТекстЗапроса = "
|SELECT $Поставка.УИД УИД
| , MAX(NullIf(Cast(Left(Журнал.DATE_TIME_IDDOC, 8) AS datetime), '17530101')) Документ_дата
|FROM $Документ.ВводОВХ AS ВводОВХ With (NOLOCK)
| INNER JOIN $Документ.Поставка AS Поставка With (NOLOCK) ON $ВводОВХ.Основание = $ВидДокумента36.Поставка + Поставка.IDDOC
| INNER JOIN _1SJOURN AS Журнал With (NOLOCK) ON ВводОВХ.IDDOC = Журнал.IDDOC
|WHERE (Журнал.DATE_TIME_IDDOC >= :д1) AND ((Журнал.CLOSED & 1) = 1)
|GROUP BY
| $Поставка.УИД
|";
ЗапросСклад.УстановитьТекстовыйПараметр("д1", ДобавитьМесяц(НачДата, -12));
ЗапросСклад.ВыполнитьИнструкцию(ТекстЗапроса, Результат);
Возврат Результат;
КонецФункции
При обращении к базам филиалов разработчики часто сталкиваются с ошибкой «Введенный пароль неверен» на строке БазаПодкл.ПрисоединитьИБ(Каталог1С), хотя через SQL Management Studio или Query Analyzer соединение по логину и паролю SQL проходит успешно.
Выясним причину такого поведения. Метод ПрисоединитьИБ открывает служебный файл 1Cv7.dba, в котором хранятся системные параметры подключения базы к СУБД. Эти данные зашифрованы внутренними механизмами платформы 1С. Для их расшифровки требуются логин и пароль пользователя 1С:Предприятия, а не учетной записи SQL Server.
Синтаксис метода с явным указанием учетных данных пользователя 1С:
БазаПодкл.ПрисоединитьИБ(КаталогИБ, ИмяПользователя1С, ПарольПользователя1С);
Если в удаленной базе настроен список пользователей, необходимо передать имя и пароль пользователя 1С, у которого есть права на открытие конфигурации (например, пользователя с административными правами). При пустом списке пользователей параметры можно опустить.
Иногда требуется в рамках одной SQL-инструкции объединить данные текущей базы и базы другого филиала (например, если они расположены на одном SQL-сервере или соединены через механизм Linked Server). По умолчанию метапарсер компоненты 1С++ умеет транслировать метаимена только одной конфигурации за один проход.
Проанализируем методику обработки текста запроса в два этапа с помощью двух независимых объектов MetaDataWork:
$.@.MetaDataWork (он преобразует имена текущей базы).MetaDataWork, подключаем к нему файл 1Cv7.md удаленной базы с помощью метода ПрисоединитьМД().@ обратно на $ и повторно вызываем метод ОбрМетаСКЛ() для преобразования имен удаленной базы.ODBCRecordSet.Посмотрим на практический пример кросс-базового запроса:
Процедура СформироватьКроссЗапрос()
Перем рс, ТекстЗапроса, глМД, глМД2, ПутьКБазе2, ТабРез;
рс = СоздатьОбъект("ODBCRecordSet");
// В тексте запроса:
// $ - метаданные текущей базы
// @ - метаданные второй (удаленной) базы
ТекстЗапроса = "
|SELECT
| СпрНаш.DESCR AS КлиентВТекущейБазе
| , СпрУдал.DESCR AS КлиентВУдаленнойБазе
|FROM $Справочник.Контрагенты AS СпрНаш With (NOLOCK)
|LEFT JOIN DatabaseBranch.dbo.@Справочник.Контрагенты AS СпрУдал With (NOLOCK)
| ON СпрНаш.CODE = СпрУдал.CODE
|";
// Шаг 1: Парсим метаимена текущей базы
глМД = СоздатьОбъект("MetaDataWork");
ТекстЗапроса = глМД.ОбрМетаСКЛ(ТекстЗапроса);
// Шаг 2: Подключаем MD второй базы и парсим оставшиеся метаимена
глМД2 = СоздатьОбъект("MetaDataWork");
ПутьКБазе2 = "\\ServerName\base\branch\";
глМД2.ПрисоединитьМД(ПутьКБазе2 + "1Cv7.md");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "@", "$");
ТекстЗапроса = глМД2.ОбрМетаСКЛ(ТекстЗапроса);
// Шаг 3: Выполняем готовый T-SQL запрос
ТабРез = рс.ВыполнитьИнструкцию(ТекстЗапроса);
ТабРез.ВыбратьСтроку();
КонецПроцедуры
Для оптимизации кода конфигурации и централизованного создания соединений (SQL Server, OLE DB, DBF, SQLite) удобно использовать универсальную функцию-обертку. Она инициализирует подключение и возвращает готовый к работе объект запроса.
Рассмотрим реализацию такой функции:
Функция глСоединение(ТипСоединения = "", ПутьИБ = "", Пользователь = "Admin", Пароль = "123456", ИмяСервера = "") Экспорт
Перем БД, Запрос, Команда, СтрокаСоединения, МФ;
Если ВРег(ТипСоединения) = "SQL" Тогда
Попытка
БД = СоздатьОбъект("ODBCDataBase");
Запрос = СоздатьОбъект("ODBCRecordSet");
Если ПустоеЗначение(ПутьИБ) = 0 Тогда
БД.ПрисоединитьИБ(ПутьИБ, Пользователь, Пароль);
Запрос.УстБД(БД);
КонецЕсли;
Возврат Запрос;
Исключение
Сообщить("Ошибка инициализации соединения SQL: " + ОписаниеОшибки(), "!");
Возврат 0;
КонецПопытки;
ИначеЕсли ВРег(ТипСоединения) = "SQL_DIRECT" Тогда
Попытка
БД = СоздатьОбъект("ODBCDataBase");
Запрос = СоздатьОбъект("ODBCRecordSet");
СтрокаСоединения = "Driver={SQL Server};Server=" + ИмяСервера + ";Database=" + ПутьИБ + ";Uid=" + Пользователь + ";Pwd=" + Пароль + ";";
БД.Соединение(СтрокаСоединения);
Запрос.УстБД(БД);
Возврат Запрос;
Исключение
Сообщить("Ошибка прямого ODBC-соединения: " + ОписаниеОшибки(), "!");
Возврат 0;
КонецПопытки;
ИначеЕсли ВРег(ТипСоединения) = "ДБФ" Тогда
Попытка
БД = СоздатьОбъект("ODBCDataBase");
Если ПустоеЗначение(ПутьИБ) = 0 Тогда
БД.ПрисоединитьИБ(ПутьИБ);
Иначе
БД.Соединение("DRIVER={Microsoft Visual FoxPro Driver};Deleted=Yes;Null=Yes;Collate=RUSSIAN;Exclusive=No;SourceType=DBF;SourceDB=" + КаталогИБ());
КонецЕсли;
Запрос = СоздатьОбъект("ODBCRecordSet");
Запрос.УстБД(БД);
Возврат Запрос;
Исключение
Сообщить("Ошибка подключения к DBF: " + ОписаниеОшибки(), "!");
Возврат 0;
КонецПопытки;
Иначе
МФ = СоздатьОбъект("MetaInfoClasses");
Если МФ.ЭтоSQL_Версия() = 1 Тогда
Возврат глСоединение("SQL");
Иначе
Возврат глСоединение("ДБФ");
КонецЕсли;
КонецЕсли;
КонецФункции
Обратите внимание на технические нюансы при работе со сторонними структурами метаданных:
ПрисоединитьИБ и ПрисоединитьМД требуют наличия прямого доступа по протоколу SMB к каталогу с базой для чтения файлов 1Cv7.md и 1Cv7.dba. Если доступен только SQL-порт (TCP 1433), следует скопировать файл 1Cv7.md локально и использовать ручную обработку текста через MetaDataWork.ПрисоединитьМД() в связке с прямым ODBC-соединением.[Ссылка $Справочник.Номенклатура] корректно возвращает рабочие ссылки только для текущей базы. Для удаленной базы парсер вернет строковые или числовые идентификаторы объектов (ID), так как контекст сторонней базы в запущенном сеансе 1С не поддерживается.