| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
Динамическое создание ДТС-пакетов с помощью VB Почти все разработчики в области DBA (Database Access) рано или поздно сталкиваются с проблемой перемещения данных между базами данных, с которыми работают их приложения. В моей статье я продемонстрирую программное решение конкретной задачи по копированию данных из таблицы формата ДБФ в базу данных MS SQL Server. Сразу оговорюсь, что мое решение не претендует на идеальность, поэтому прошу помидорами не закидывать. Итак, передо мной стояла задача: нужно из какой-то точки локальной сети доступной серверной машине переместить данные, которые находятся в таблице формата ДБФ в базу данных MS SQL Server, причем база данных на сервере - произвольная, сервер тоже. Опять же у Вас могут быть вопросы, что типа, зачем это нужно и все такое, оказалось, что это вполне реальная задача при большом потоке входных файлов в формате ДБФ. Задачу я разбил на две подзадачи: 1 - получить информацию о структуре ДБФ файла. 2 - собственно загнать файл на сервер. Ну, первая это задачка можно сказать. Опытный ДБА программер предложит довольно много способов ее решения. Так как мы с Вами ВБ - эшники, то мы это сделать тоже можем довольно многими способами. После перебора нескольких из них я остановился на использовании широко известном обществу универсального провайдера данных MS ADO. Вторую задачу можно тоже решать достаточно многими способами. Я, выбрал не самый легкий путь - использование Microsoft DTS Package Object Library - dtspkg.dll. Что это? Это ActiveX in-process DLL, которая появляется на машине после установки на ней MS SQL Servera (\Mssql\Binn\Dtspkg.dll). Именно она вызывается, когда Вы ручками конфигурируете DTS пакет в MS SQL, вызываете каким-либо способом пакет и т.д. Компонент позволяет программно контролировать ДТС пакеты. Весит он 1,85 мБ. Само использование таких довольно тяжело переносимых объектов (особенно dtspkg.dll) привело к решению о том, что программу лучше не таскать по куче компов, а поставить на сервере и сделать удаленно выполняемой. Т.е. использовать механизм Remote Automation (удаленной автоматизации) он же RPC (Remote Procedure Calling - удаленный вызов процедур). Идея в том что реально клиентская программа находится на каком-то сетевом компе и получает от удаленно выполняемого out-process EXE-server-а экземпляры классов (объектов) которые реализуют свойства и методы для решения поставленной задачи. По сути ничего необычного в этих объектах нет, с той лишь разницей, что выполняются они на сервере. Всем известная выгода таких объектов - при хорошей сетке сервер исполняет код гораздо быстрее, чем клиент, в качестве которого на моей работе попадаются даже четверки. Итак, класс являться контейнером для dtspkg.dll, а для получения структуры ДБФ файла использует АДО. Весь код класса Вы можете прочитать, скачав исходник. Я остановлюсь подробнее только на некоторых ключевых моментах и возможных подводных камнях. Класс состоит из четырех внутренних функций и одной внешней. Внутренняя функция get_structure решает задачу получения структуры файла. Для идентификации типов полей и их размеров использует вторую внутреннюю функцию fild_type. Функция get_structure в качестве аргументов принимает путь к папке, в которой лежит ДБФ-таблица и имя таблицы. В качестве результата функция возвращает динамический двухмерный массив. В первой колонке - имя поля, во второй - его тип данных и размер (если поле текстовое). Обратите внимание, что для установления соединения к ДБФ-таблице используется Microsoft OLE DB Provider for ODBC Drivers: db.Open "Provider=MSDASQL.1;Persist Security Info=False;Mode=ReadWrite;Extended Properties=Driver={Microsoft FoxPro VFP Driver (*.dbf)}; UID=;SourceDB=" & path & "; SourceType=DBF;Exclusive=Yes;BackgroundFetch=Yes; Collate=Machine;Null=Yes;Deleted=Yes;" Рекомендую использовать версию MDAC не ниже 2.5. Программа тестировалась на Win2K Professional и Server. Проблем с ADO естественно не было. После успешного соединения к папке с таблицей, открывается рекордсет lrs. lrs.Open "select * from " & target_table, db, adOpenKeyset, adLockOptimistic Приводим размер динамического массива к матрице размера количество полей х 2. ReDim Preserve ff(lrs.Fields.Count - 1, 2) Перемещаемся циклом по коллекции полей Fields. For i = 0 To lrs.Fields.Count - 1 В первый столбец массива вносится имя поля. Во второй через вызов функции fild_type его тип. После выхода из цикла присваиваем результат - результату функции. Затем нормальный выход. get_structure = ff Функция fild_type в качестве аргумента принимает АДО-поле и в зависимости от его типа возвращает аналогичный тип поля SQL. Номера типов были получены опытным путем - прогонкой всех имеющихся в наличии ДБФ-ов через неё. Можно конечно было просто перечислить весь DataTypeEnum, однако для конкретного АДО-провайдера(в данном случае VFP) эти константы будут разные. Например, 133 это adDBDate хотя есть и 7 - adDate, но VFP провайдер такой Type не разу не показал и т.д. Если какого-то типа здесь не окажется, я не виноват. Select Case f.Type Для текстовых полей добавляется еще и их размер. Внешняя функция trans непосредственно получает аргументы от приложения - клиента. Согласно этим аргументам проводит конфигурирование ДТС - пакета и затем его выполняет, что приводит к переносу данных из ДБФ - таблицы на сервер. Аргументы функции: path_to_source_file - путь к копируемому файлу, target_server - SQL сервер на который будем переносить, Dbase_on_the_server - БД на этом сервере - она получит таблицу, file_to_transer - имя ДБФ-таблицы. Dim goPackage As New DTS.Package Это создается объектная переменная goPackage объекта DTS.Package. DTS.Package - самый верхний в иерархии Microsoft DTSPackage Object Library:
Dim oConnection As DTS.Connection В коллекцию Connections добавляются два объекта Connection содержащие информацию о соединениях к OLE DB сервис-провайдерам. На схеме соответственно показано визуальное отображение этих объектов: Connection 1 и Connection 2 (обозначены цифрами 1 и 2). Dim oStep As DTS.Step В коллекцию Steps (шаги) добавляются два объекта Step, которые содержат информацию о схеме(flow) пакета и выполняемых им задачах. Опять же на схеме шаги это два выделенных цветом вектора, показывающие направление исполнения пакета (цифры 3 и 4). Dim fs() As String Вызов функции get_structure для получения структуры таблицы. Вызов происходит в этом месте т.к. структура перемещаемой таблицы сейчас понадобится первый раз. Dim oTask As DTS.Task Здесь на первый взгляд запутанное присвоение объектных переменных вызвано оригинальностью иерархии (см. рис.)
oCustomTask1.Name = "Create Table [" & Dbase_on_the_server & "]. [dbo].[" & file_to_transer & "] Task" В коллекцию задач Tasks добавляется объект Task, CustomTask которого это ExecuteSQLTask (на схеме это элемент с названием Create Table и номером 5). При запуске пакета эта задача будет первой операцией, которая будет производить какие-либо физические операции с БД. А именно создаст, пустую таблицу в БД на сервере согласно свойству CustomTask.SQLStatement. В него дополнительно к обычному SQL выражению Create Table добавлена проверка на существование таблицы с таким же именем (выражение if exists:). Если таблица уже есть она будет удалена. Таким грубым образом избегаем ошибки существования таблицы, наверное, знакомой многим пользователям ДТС-пакетов. В SQLStatement также присутствует вызов вспомогательной внутренней функции c1, которая разворачивает массив в одну строку вида: Dim oCustomTask2 As DTS.DataPumpTask, i As Integer В коллекцию задач Tasks добавляется второй объект Task, CustomTask которого это DTSDataPumpTask (на схеме это вектор который совпадает с одним из векторов Step - номер 6). DTSDataPumpTask - это OLE DB сервис-провайдер который импортирует, экспортирует или трансформирует данные между гетерогенными источниками данных. Свойство oCustomTask2.SourceSQLStatement сделает выборку из исходного ДБФ-файла. Функция c2 разворачивает массив в строку вида: `имя поля1`, `имя поля2` : `имя поляN` Ниже показана иерархия объектов DTSDataPumpTask:
Set oTransformation = oCustomTask2.Transformations.New("DTS.DataPumpTransformCopy") В коллекцию задач Transformations добавляется объект Transformation содержащий информацию о преобразовании колонок исходной таблицы к полям таблицы получателя. ... Циклом перебираем поля источника и устанавливаем значения переменных ordinal (позиция поля), name (имя поля), flag (определяет DBCOLUMNFLAGS), size (макс. размер поля, для текстовых), datatype (тип даннях поля). ... Наполняем коллекцию колонок источника SourceColumns. ... Наполняем коллекцию колонок получателя DestinationColumns. ... Последние команды, заполняющие коллекцию преобразований и задач. Таким образом, все объекты, показанные на визуальной схеме пакета, сконфигурированы. Пакет готов к выполнению. 'goPackage.SaveToSQLServer target_server, "sa", "s" Закомментированная строчка сохраняет пакет на сервере. goPackage.Execute - выполняет. Объект уничтожается и происходит нормальный выход из функции.
Private Sub Form_Load() На сервер в \\rrp\d\test кладу десяток ДБФ-в. Private Sub Command1_Click() Здесь SQL-сервер scooter, база - test, копируемый файл Rab.dbf. Нажми кнопку и получишь таблицу на сервере. Private Sub Command2_Click() Здесь все тоже только копируем на сервер в цикле пачку таблиц. |
|
| ||||||||||||||||
|