Visual2000 · Архив статей Колесова & Павловой

VB 6.0: доступ к данным с помощью технологии ADO
Часть 2. Переход от DAO к ADO: это вполне реально

Андрей Колесов, Ольга Павлова

© 1999, Андрей Колесов, Ольга Павлова
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" № 07/99, c. 158-165.


О чем пойдет речь дальше

Миграция от одной технологии к другой никогда не проходит безболезненно, и переход от DAO к ADO не является исключением. Вы не можете просто поставить переключатель или запустить имеющуюся под рукой утилиту, которая выполняет необходимые изменения в программном коде доступа к данным. Необходимо обдумать каждый фрагмент кода и провести миграцию вручную, шаг за шагом осуществляя перевод только одной порции кода. Такое преобразование требует от вас знания фундаментальных отличий между двумя моделями, так как оптимальное использование разных средств требует порой серьезной переработки программ на уровне алгоритмов.

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

В этой статье мы покажем, как планировать свою стратегию миграции в контексте решения различных задач преобразования DAO в ADO. Расскажем о том, чем объектная модель ADO отличается от аналогичной модели DAO, и попробуем объяснить на примерах, как использовать эти различия для создания более эффективного кода. Кроме того, мы продемонстрируем, что следует делать в тех случаях, когда в ADO отсутствуют прямые эквиваленты основных функций DAO, а также как воспользоваться преимуществами новых функций ADO в целях получения более широких возможностей управления хранимыми процедурами и другими аспектами программирования баз данных.

Процесс преобразования следует начинать с изучения существующей объектной модели DAO-приложения и анализа методов, подлежащих изменению. Возможные варианты модификации можно сгруппировать в три категории в зависимости от наличия эквивалентных функций в DAO и ADO (табл. 3).

Категория 1 содержит элементы, для которых объекты DAO и ADO имеют аналогичные методы, поэтому реализация данных функций в ADO требует проведения лишь незначительных изменений.

Категория 2 включает функции объектов DAO, для которых не существует прямого эквивалента в объектах ADO. Однако это не означает, что вы не можете заново создать такую функцию в ADO — просто делать это надо по-другому.

Категория 3 соответствует случаю, когда в ADO имеются функции, не существовавшие в DAO. С точки зрения проблемы миграции этот случай не является первоочередным: сначала нужно обеспечить работу уже реализованных алгоритмов. Однако здесь нужно помнить, что простая замена старых функций на однотипные новые может порой привести даже к снижению производительности приложения. Реальный эффект может быть достигнут именно за счет использования принципиально новых возможностей современных технологий, хотя для этого, может быть, понадобится структурная перестройка программы. В этом плане разработчик серьезно упростит себе жизнь, если будет ориентироваться на будущий переход в ADO.

Однако наиболее распространенным и простым является случай, когда для функций DAO имеются аналогичные средства ADO. Поэтому мы сконцентрируемся в основном на этом типе преобразований, используя для прояснения деталей конкретные примеры. Тем не менее отсутствие прямого, "один-к-одному", эквивалента между DAO и ADO совершенно не означает, что в ADO нет функциональных возможностей, которые ранее присутствовали в DAO. Напротив, ADO содержит альтернативные методы для достижения ваших бизнес-целей — методы, как правило, более простые в использовании, более быстрые и более масштабируемые, особенно при работе с удаленными базами данных.

В начало статьи

Операции поиска

DAO содержит ряд полезных функций, которых вам будет недоставать при миграции в ADO. Например, DAO включает пять методов поиска: FindFirst, FindLast, FindPrevious, FinfNext и Seek. Они очень полезны, но имеют ряд недостатков.

Во-первых, использование явных методов поиска записей довольно трудоемко, поскольку требует повторного написания одного и того же кода для каждого метода, которому затем передают один и тот же критерий. Во-вторых, они эффективно работают только с локальными базами данных; их использование при поиске на удаленных базах данных существенно снижает производительность программ. Именно поэтому ADO не включает эти команды в свою объектную модель, но предлагает другие средства для решения аналогичных задач.

Для операций поиска и перемещения по базе данных с помощью ADO применяют один метод Find, который использует несколько параметров для воспроизведения многих функций из модели DAO, в том числе и пять перечисленных выше (рис. 1 и 2).

Рис. 1. Почувствуйте разницу. Внешне все осталось по-прежнему, но внутри произошли серьезные изменения. ADO "сплющивает" объектную модель DAO, заменяя несколько сходных методов одним, содержащим больше свойств, методов и аргументов. Это не только упрощает программирование ядра базы данных, но и делает написанный вами код более эффективным, а также позволяет вам создавать эквивалентные решения за меньшее время

Рис. 2. Для ADO не существует прямого, "один-к-одному", способа преобразования объектов и методов DAO. Вместо этого ADO содержит меньше объектов, которые содержат больше параметров, свойств и аргументов. Так, ADO сжимает объекты DBEngine, Workspace и Database в один объект Connection; пять методов поиска объектов DAO в один метод Find; объекты TableDefs и QueryDefs в один объект Command. В результате вы имеете в своем распоряжении простую, более удобную в использовании и намного лучше масштабируемую объектную модель

В этом и состоит характерное отличие ADO от DAO: новая модель содержит меньше объектов, но вместе с тем больше свойств, методов и аргументов. В результате объектная модель становится более понятной.

Возьмем, к примеру, метод Find объектов ADO. Он находит следующую запись в объекте Recordset, отвечающую определенному условию, а затем делает ее текущей записью. Этот метод используется для нахождения конкретной записи в объекте Recordset с помощью фразы Where в стиле SQL, заданной пользователем: Recordset.Find Criteria, SkipRecords, SearchDirection, Start. Метод Find в ADO поддерживает четыре аргумента, но чаще всего ему требуется только один — Criteria.

Остальные аргументы используют значения, предустановленные по умолчанию, если вы не задали для них значения в явном виде. Параметр Criteria задает критерий, который необходим для нахождения записи в объекте Recordset. Первый необязательный параметр, SkipRecords, задает величину типа Long, указывающую количество записей, которые следует пропустить при нахождении конкретной записи в объекте Recordset. По умолчанию данное значение устанавливается как 0 — это означает, что текущая запись не пропускается. Последующие вызовы метода Find устанавливают используемое по умолчанию значение параметра SkipRecords как 1 — это означает, что нужно перейти на одну запись вперед, до тех пор пока не будет найдена следующая запись, отвечающая критерию поиска.

Третий параметр, SearchDirection, указывает направление, в котором должен осуществляться поиск — вперед (0 или константа AdSearchForward) или назад (1 или AdSearchBackward), то есть обеспечивает функциональные возможности методов FindNext и FindPrevious в DAO. SearchDirection служит иллюстрацией того, как ADO "сплющивает" объектную модель DAO: один параметр позволяет заменить два метода поиска.

Последний параметр метода Find — Start, имеющий тип Variant и задающий место, с которого следует начинать поиск. Он представляет собой либо допустимую закладку, либо числовое значение закладки, которая определяет место, с которого начинается поиск: текущая (0 или AdBookmarkCurrent), первая (1 или AdBookmarkFirst) или последняя запись в объекте Recordset (2 или AdBookmarkLast).

Метод Seek выполняет самый быстрый способ адресации записи, а также изменения порядка поиска при изменении свойства Index объекта Table. Но Seek применим только к объекту Table, то есть его нельзя использовать при работе с динамическими наборами записей (dynasets). В то же самое время другие четыре метода поиска DAO применимы к объекту Recordset, а не к Table (вместо Seek используется комбинация FindFirst и FindNext).

В объектах ADO в качестве эквивалента Seek можно применять все тот же метод Find. Однако здесь необходимо подчеркнуть следующие моменты. Метод Find воспринимает только одно значение поиска, поэтому вы не можете выполнять несколько операций поиска с помощью операторов AND или OR. Это означает, что для выполнения подобной задачи в ADO следует применять несколько другой подход. К примеру, вы можете использовать свойство Filter объектов ADO, которое воспринимает несколько значений.

Свойство Filter меняет свой тип из String для объектов DAO в Variant для объектов ADO; тем не менее его основные функциональные возможности остаются неизменными. Свойство Filter устанавливает или возвращает величину типа Variant, которая содержит строковую переменную Criteria (состоящую из одной или нескольких фраз) и массив уникальных значений закладки, указывающие на записи в объекте Recordset.

В начало статьи

Попробуем на примере

Конечно, теория — это одно, а написание кода — совсем другое. Предположим, что у нас есть некоторый код для объектов DAO, который выполняет несколько операций поиска (листинг 1), и мы хотим перейти к объектам ADO, сохранив неизменными критерий и механизм поиска. Начнем с того, что найдем все методы поиска объектов DAO. В первую очередь займемся методами FindFirst и FindNext, поскольку их легче всего преобразовать. Для их замещения применим метод Find объектов ADO с тем же самым критерием (листинг 2). Используем один из необязательных параметров этого метода, чтобы поиск осуществлялся в направлении вперед. Затем уничтожим свойство NoMatch, поскольку оно не существует в объектах ADO; вместо него напишем recordset.EOF. Это означает, что процедура поиска записей будет происходить до тех пор, пока не будет достигнут конец файла.

FindPrevious тоже легко преобразуется; для этого необходимо в методе Find установить направление поиска как обратное. И наконец, остается метод Seek, который не имеет прямого эквивалента в объектах ADO. Более того, разные разработчики используют его по-разному. Вы можете, например, захотеть заменить его методом Find. Такое решение в большинстве случаев является работоспособным, однако, если процесс поиска будет занимать слишком много времени, вам придется переписать код с целью его оптимизации.

Подход, который используется для поиска и нахождения записей в объектах ADO, является одним из наиболее критичных проектных решений. Вам может показаться утомительным ждать окончания поиска, особенно если вы уже знаете, какие данные, скорее всего, получите. Объекты ADO содержат альтернативные решения для таких случаев. Например, если вы собираетесь искать подмножества данных, то можно создать временную таблицу, содержащую только те строки и столбцы, которые, по вашему мнению, пригодятся в будущем. Проиндексировав ее, вы увеличите скорость доступа к данным. Следует также иметь в виду, что для разных методов доступа наиболее эффективными будут различные алгоритмы поиска.

В начало статьи

Объекты ADO требуют нового подхода

Миграция от объектов DAO к объектам ADO в тех случаях, когда существуют аналогичные функции, является простой, хотя и требует много времени. Другие аспекты преобразования могут быть более сложными и занимать еще больше времени. Иногда процесс миграции может включать в себя несколько видов преобразований. Так, объект Properties существует как в DAO, так и в ADO, однако в последнем случае он служит иной цели. В DAO объект Properties используется из объекта Document для получения атрибутов базы данных Jet. А вот в ADO коллекция Properties служит для получения конкретной информации о следующих объектах: Connection, Recordset или любом другом.

Кроме того, вам необходимо уделить особое внимание транзакциям, которые попадают во вторую категорию (табл. 3). Объекты ADO поддерживают транзакции, но они реализуются совсем по-другому. Например, объект Workspace обеспечивает в DAO гибкое выполнение транзакций, которые охватывают несколько баз данных. Однако в ADO нет такого объекта, и поэтому вам необходимо реализовать другой механизм выполнения транзакций.

Категория 2 содержит множество операций DAO по работе с данными, и их преобразование в ADO может показаться сложным. Но можно упростить эту задачу, если вы не будете пользоваться функциями, относящимися к базе данных Jet. DAO содержит три объекта самого высокого уровня: DBEngine, Workspace и Database. В ADO вы заменяете все эти объекты на объект Connection, который управляет установлением связи с базой данных и созданием объектов Recordset (листинг 3).

Простой в использовании объект Connection позволяет связать потребителя данных с их провайдером. При этом нет необходимости создавать объекты связи в явном виде. Напротив, вы можете передать связь напрямую в объект Command или Recordset. Тем не менее, создание объекта Connection в явном виде может увеличить производительность в тех случаях, когда вам необходимо совершить несколько "заходов", чтобы получить данные от провайдера. Аналогично, вы можете заменить TableDefs и QueryDefs, входящие в DAO, на один объект Command из ADO. Этот объект позволяет обрабатывать операторы и запросы SQL, например хранимые процедуры, что объединяет всю работу с SQL в рамках одного объекта Command.

Объект Index в DAO определяет порядок просмотра записей таблиц баз данных. А метод OpenSchema позволяет получать информацию с помощью запроса перечислимого типа. В ADO у вас нет возможности создавать сами индексы, однако методы сортировки, входящие в метод Sort, и использование клиентского курсора могут дать указание ядру базы данных создать временный индекс для каждого поля. Тем не менее, если вы хотите создавать индексы в явном виде, необходимо самостоятельно обеспечить эту функциональную возможность (в виде SQL-оператора или хранимой процедуры).

В начало статьи

Уникальные функции объектов ADO

Работа с функциями ADO, не входящими в DAO (категория 3) может быть как более простой, так и более сложной: все зависит от степени использования новых функций ADO. Например, можно поступить так, как делали многие программисты при переходе с VB3 на VB4: преобразовывать только базовые функции и методы, но ничего лишнего. Значительная часть разработчиков до сих пор пишет программный код в VB5 и VB6 точно так же, как они это делали в VB4, — избегая использования классов и возможности создавать элементы управления непосредственно в VB. Такой подход упрощает проведение преобразований и обеспечивает более высокий уровень поддержки со стороны Microsoft, но в то же самое время вы можете упустить новые важные функции. Не всегда имеет смысл выполнять что-либо по-старому, когда новые версии продукта предоставляют лучшие возможности.

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

Новые функции объекта Command в ADO предоставляют более широкие возможности управления хранимыми процедурами, упрощая тем самым выполнение таких операций. Данный объект запускает одну команду, используемую для выполнения запросов, которые либо возвращают набор записей, либо нет. Эту команду можно также применять для создания готовых операторов, сохраняющих значения команды, которую вы хотите выполнить впоследствии, а также для уничтожения связи после выполнения оператора.

Наиболее значимые из новых возможностей ADO — "сплющенная" объектная модель и усовершенствованная масштабируемость доступа к локальным и удаленным базам данных — могут служить основополагающими причинами перехода от DAO к ADO. Последняя технология еще далеко от совершенства — содержащиеся в ней в настоящий момент ошибки достаточно серьезны, — но она позволяет вам делать намного больше и с меньшими усилиями, особенно при доступе к удаленным данным. Однако эти усовершенствования не даются бесплатно — вам необходимо пересмотреть всю свою методологию при миграции к ADO. Примеры, приведенные в этой статье, являются лишь иллюстрацией наиболее типичных вопросов, которые следует решать при переводе программного кода. Выполнение такого преобразования требует больше, чем переработка кода вручную, — оно должно сопровождаться тщательным тестированием и использованием пошагового подхода. Прежде чем изменить всего одну строку кода, следует разработать стратегию всего преобразования (см. приложение "Разработка эффективной стратегии миграции").

VBP-проекты примеров, приведенных в данной статье, вы можете найти на Web-узле по адресу: www.visual.2000.ru/develop/vb/source/.

В начало статьи

ПРИЛОЖЕНИЯ

В начало статьи

Таблица 3. Разбиение существующего DAO-кода на категории

  Объекты DAO Объекты ADO
Категория 1
Функции объектов DAO, для которых существует аналогичный подход в объектах ADO
Database connections
Fields Objects
Error Objects
Transactions
Properties
Recordsets
Connections
Database connections
Fields Objects
Error Objects
Transactions
Properties
Recordsets
Connections
Категория 2
Функции объектов DAO, которых нет в объектах ADO
Workspace Object
Database Object
TableDefs Object
QueryDefs Object
Index Object

Специальные Jet-функции:
    Groups/Users Object
    Relations Object
    Containers Object
    Document Object
    Properties Object
 
Категория 3
Функции объектов ADO, которых нет в объектах DAO
  Events
Command Object
Disconnected Recordsets

Примечания к таблице

Процесс преобразования следует начинать с изучения существующей объектной модели DAO-приложения, централизации и абстракции методов, подлежащих изменению. Следующим шагом должно стать разбиение существующего кода на три рассматриваемые здесь категории.

Категория 1 содержит элементы, для которых объекты DAO и ADO имеют аналогичные методы, поэтому реализация данных функций в ADO требует проведения лишь незначительных изменений.

Категория 2 включает функции объектов DAO, для которых не существует прямого эквивалента в объектах ADO. Однако это не означает, что вы не можете заново создать такую функцию в ADO? — просто это надо делать по-другому.

Вас может заинтересовать, почему следует преобразовывать существующий DAO-код в Категорию 3. В конце концов если в DAO нет данной функции, то и не следует переносить ее в ADO в первую очередь. Хотя это верно, но только отчасти. У вас есть возможность преобразовать DAO-код в ADO, не используя при этом никаких новых уникальных функциональных возможностей ADO. Однако при этом вы теряете большую часть преимуществ, предоставляемых объектами ADO, а именно: сообщение о наступлении события, более простое и точное управление хранимыми процедурами и возможность выполнять операторы в заранее определенное время или при заранее установленных условиях. Тщательно спланированная миграция включает не только преобразование DAO в прямой ADO-эквивалент, но и использование преимуществ, связанных с отличием двух моделей, для усовершенствования существующего программного кода.

В начало статьи

Листинг 1

Метод FindNext объектов DAO позволяет находить записи, отвечающие заданному критерию поиска. Он дает возможность просматривать весь набор записей, до тех пор пока вы не достигните конца файла. С помощью данного метода можно также осуществлять выборку только одной записи.

Dim sCriteria As String
'
' Устанавливает курсор мыши в виде песочных часов
Screen.MousePointer = 11
' Очищает элемент управления ListBox
List1.Clear
'
' Устанавливает критерий поиска
sCriteria = "Author Like " & "'" & Text1.Text & "'"
'
If Check1.Value = 0 Then
   While rs.EOF = False
     rs.FindNext sCriteria
     If rs.NoMatch = False Then List1.AddItem rs.Fields("Author")
     rs.MoveNext
   Wend
Else
   rs.FindNext sCriteria
   List1.AddItem rs.Fields("Author")
End If
'
Text4.Text = List1.ListCount
'
' Возвращает курсор мыши в исходное состояние
Screen.MousePointer = 0

В начало статьи

Листинг 2

ADO позволяет заменить пять методов поиска объектов DAO на один метод Find. Данный пример демонстрирует, как продублировать все функциональные возможности метода FindNext. Используйте такой же подход при обновлении каждого из оставшихся четырех методов поиска.

Dim sCriteria As String
On Error Resume Next
'
sCriteria = "Author Like " & "'" & Text2.Text & "'"
'
' Устанавливает курсор мыши в виде песочных часов
Screen.MousePointer = 11
' Очищает элемент управления ListBox
List2.Clear
'
If Check1.Value = 0 Then
  While adors.EOF = False
    adors.Find sCriteria, adSearchForward
    List2.AddItem adors.Fields("Author")
    adors.MoveNext
  Wend
Else
  adors.Find sCriteria, adSearchForward
  List2.AddItem adors.Fields("Author")
  adors.MoveNext
End If
'
' Получает количество записей
Text5.Text = List2.ListCount
'
' Возвращает курсор мыши в исходное состояние
Screen.MousePointer = 0

В начало статьи

Листинг 3

Объект Connection в ADO заменяет объекты Database и DBEngine из DAO. Например, можно вернуть набор записей, создав функцию "заворачивания", которая может вызываться из любого клиента или любого раздела кода. Объект Command в данном примере вызывает хранимую процедуру, но вы можете изменить ее для своих конкретных целей.

Function RetrieveRecordSet() As ADODB.Recordset
  Dim rsset As ADODB.Recordset
  Dim cn As ADODB.Connection
  Dim connectstring As String
  Dim anerror As ADODB.Error
  Dim Sql As String
  Dim cmdStoredProc As New ADODB.Command
  '
  cmdStoredProc.Prepared = False
  cmdStoredProc.CommandText = "getauthorinfo"
  cmdStoredProc.CommandType = adCmdStoredProc
  connectstring = "Driver=SQL " & _
          "Server;Server=FASDEVSPHINX;Database=pubs;UID=sa;"
  '
  Set cn = New ADODB.Connection
  cn.ConnectionString = connectstring
  cn.CursorLocation = adUseClient
  cn.Open
  '
  Set cmdStoredProc.ActiveConnection = cn
  Set rsset = cmdStoredProc.Execute
  Set RetrieveRecordSet = rsset
End Function

В начало статьи

Разработка эффективной стратегии миграции

  1. Начните с организации и анализа существующего DAO-приложения.
  2. Сгруппируйте функции DAO-приложения в несколько абстрактных слоев.
  3. Составьте план пошаговых изменений и тестирования.
  4. В первую очередь преобразуйте элементы, относящиеся к категории 1.
  5. Рассмотрите альтернативы для преобразования функций, отсутствующих в объектах ADO.
  6. Перейдите к работе с элементами из категории 2.
  7. Изучите новые функциональные возможности объектов ADO с целью их добавления к своему приложению.

В начало статьи