Что такое код ado


Содержание

13. Применение ADO и работа с базами данных

Объектная модель ADO (ActiveX Data Objects) в скриптах VBScript, взаимодействие с базами данных из VBScript, MDAC (Microsoft Data Access Components), объекты ADO.Connection, Recordset и Command

13.1 Что такое ADO

ADO расшифровывается как ActiveX Data Objects — набор программных объектов, построенных по технологии ActiveX ( COM ) и позволяющий получать данные и управлять ими на самых разных источниках. Другие наборы программных объектов для доступа к источникам данных, которые часто используются в скриптах — это DAO и RDO , но эти программные объекты устарели и к использованию в современных приложениях не рекомендуются. В настоящее время появилась новая версия ADO — ADO . NET , которая сильно отличается от обычной ADO и предназначена для работы в . NET Framework . Однако по причине того, что ADO . NET :

· обязательно требует установленной . NET Framework (чего на многих старых компьютерах нет)

· обычными средствами с ADO . NET работать не получится — требуется Visual Studio . NET ;

· отличается повышенной ресурсоемкостью

ADO . NET в этом курсе рассматриваться не будет.

ADO умеет работать с самыми разными драйверами для подключения к базам данных, например, с драйверами OLE DB и ODBC . Поскольку ADO построен по технологии COM , эти объекты можно использовать в любых COM -совместимых языках программирования ( VC ++, Visual Basic , Deplhi , VBA , VBScript , JScript , ActivePerl и т.п.).

Сами программные объекты поставляются в наборе драйверов для подключения к базам данных, которые называются MDAC ( Microsoft Data Access Components ). Этот набор драйверов можно совершенно бесплатно скачать с Web -сайта Microsoft . Настоятельно рекомендуется отслеживать появление новых версий MDAC и устанавливать их на компьютерах пользователей.

Официальная документация по ADO содержится в MDAC Software Development Kit , который также можно бесплатно скачать с Web -сайта Microsoft . Множество дополнительной информации, примеров и т.п. можно найти в MSDN (искать на » ADO API Reference «, например, » ADO 2.8 API Reference » и TechNet . Наглядные примеры и хорошие рекомендации по практическому применению имеются в курсах MOC .

Главные объекты ADO выглядят следующим образом:

· объект Connection — позволяет установить соединение с источником данных и управлять им. Все ошибки, которые возникают в ходе работы соединения, помещаются в сопутствующую коллекцию Errors .

· объект Command — представляет команду, при помощи которой производится выполнение определенной операции на источнике данных (выполнение запроса, хранимой процедуры, создание или изменение объекта, изменение данных и т.п.). Если источник данных — SQL -совместимый, то объект Command , скорее всего, будет представлять команду SQL . Объекту Command сопутствует коллекция Parameters — параметры, которые передаются запросу или хранимой процедуре.

· объект Recordset — представляет набор записей, полученных с источника или сгенерированный другим способом. Ему сопутствует коллекция Fields , представляющая информацию о столбцах в этом наборе записей (имя, тип, размерность данных и т.п.), а также сами данные.

Для каждого из этих трех объектов предусмотрена также коллекция Properties , которая определяет соответственно свойства соединения, команды или набора записей.

Все объекты явно создавать необязательно — например, при создании объекта Recordset можно в автоматическом режиме создать объект Connection .

Для того чтобы использовать возможности ADO , необходимо, чтобы эта библиотека была установлена на компьютере. Вместе с Windows 2000 поставляется ADO версий 2.0 и 2.1. Весь код, который приведен в методичке, проверен на работоспособность под этой версией, и поэтому дополнительно устанавливать на компьютеры обычно ничего не требуется.

На момент создания этого курса последней версией MDAC (и, соответственно, библиотеки ADO ) была версия 2.8. В этом курсе мы будем работать именно с ней.

Что такое код ado

Для работы с данными ваше приложение может использовать различные технологии. Это Open DataBase Connectivity (ODBC), Data Access Objects (DAO), Remote Data Objects (RDO), ActiveX Data Objects (ADO) и Object Linking and Embedding DataBase (OLE DB). На выбор конкретной технологии больше всего влияния оказывают такие факторы, как функциональность, легкость программирования, удобство сопровождения и производительность. Иногда бывает важно получить доступ к данным «аккуратно», другой раз на первом месте стоит скорость работы с данными. Вопросы удобства и простоты развертывания и сопровождения, думаю, очевидны. Также нужно принимать во внимание возможность работы с одними и теми же данными нескольких пользователей — система должна поддерживать несколько подключений к базе данных без заметного снижения произоводительности. Вкратце охарактеризуем самые распространенные технологии доступа к данным:

Open DataBase Connectivity (ODBC): это API для доступа к реляционным базам данных. ODBC используется для подключения к БД, выполнения операторов SQL и получения результирующих наборов данных. ODBC позволяет приложениям «общаться» с различными системами управления базами данных (СУБД), используя один и тот же программный код.

Data Access Object (DAO): технология доступа к данным, разработанная для использования преимущественно с базами данных Jet, например, Microsoft Access или БД ISAM, такими как dBase, FoxPro и т.д.

Remote Data Objects (RDO): тонкая надстройка над ODBC, обеспечивающая соединение с БД, создание результирующих наборов данных, курсоров и выполнения хранимых процедур. Технология RDO была создана для работы с такими СУБД, как, например, SQL Server и Oracle.

OLE DB: сегодня приложения работают на различных платформах — настольных, мэйнфреймах или в интернете. Данные, с которыми приходится работать этим приложениям, могут находится в различных хранилищах данных — электронные таблицы, персональные базы данных и т.д. Такие технологии, как ODBC, DAO или RDO неспособны извлекать данные из любых источников. Для решения этой проблемы компания Microsoft разработала универсальную стратегию доступа к данным — Universal Data Access Strategy (UDA). Эта стратегия основана на COM. OLE DB — набор COM-интерфейсов, разработанных на основе концепций UDA, реализующих различные сервисы реальных хранилищ данных. Технология предназначена для доступа к реляционным и нереляционным источникам данных, включая мэйнфреймовые ISAM базы данных, системы электронной почты, текстовые файлы и т.д. — все зависит от местоположения данных.

Архитектура OLE DB состоит из потребителей данных (Data Consumers), провайдеров данных (Data Providers) и серверных компонент (Server Components). Потребитель — программный компонент, использующий интерфейс OLE DB. Среды разработки, такие как Power Builder, Delphi и языки программирования типа Visual Basic, Visual C++ — примеры потребителей.

Провайдер — программный компонент, реализующий интерфейс OLE DB. Провайдер может быть быть как провайдером данных (Data Provider) так и провайдером сервисов (Service Provider). Провайдер данных — программный компонент, представляющий свои данные в табличной форме, называемой набором строк ( rowsets ). СУБД, базы данных — примеры провайдеров данных. Этот тип провайдера является владельцем данных. Провайдер сервисов — компонент, который реализует сервисы («обработчики»), такие, например, как обработчик (процессор) запросов. Провайдеры сервисов не владеют данными.

ActiveX Data Objects (ADO): технология DAO оптимизирован для работы с базами данных Microsoft Access. RDO создано для доступа к СУБД типа SQL Server или Oracle с использованием ODBC. ActiveX Data Objects (ADO) — наследник технологий DAO и RDO. ADO объединяет все лучшее из DAO и RDO. ADO использует технологию OLE DB для доступа к данным из любого источника.

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

Объектная модель ADO основана на трех типах объектов — подключение ( Connection ), команда ( Command ) и набор данных ( Recordset ). Объект Connection хранит информацию о подключении к источнику данных, такую как имя, местоположение данных, имя пользователя и пароль, имя провайдера OLE DB и т.д. Объект типа Command используется для выполнения операторов SQL, хранимых процедур и т.д. Объект Recordset хранит результаты выполнения запросов. Далее приводятся типичные алгоритмы работы с этими тремя видами объектов:

Для подключения к источнику данных нужно:


    Объявить указатель на объект типа Connection

Создать объект Connection

p.CreateInstance ( __uuiof ( Connection ) ) ;

Открыть источник данных

p->Open ( data provider, data source name, user name, password ) ;

По окончании работы с данными закрыть соединение

Для создания объекта типа Command нужно:


    Объявить указатель на объект типа Command

Создать объект типа Command

p1.CreateInstance ( __uuidof ( Command ) ) ;

Сформулировать текст запроса

p1->CommandText = » …. Actual command …»

Указать тип команды

CommandType — свойство, которое может принимать предопределенные значения, такие как AdCmdTable , AdCmdStoredProc , AdCmdUnknown .

Для использования объекта типа Recordset нужно:

Объявить указатель на объект типа Recordset

Создаем объект Recordset

p2.CeateInstance ( __uuidof ( recordset ) ) ;

p2 -> CommandText = «… Actual command ….» ;

Выполнить запрос и получить результирующий набор данных

Закрыть Recordset
p2->Close( ) ;

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

В этой статье приводится детальное описание создания программы для манипуляций (добавления, изменения, удаления) со строками таблицы БД Microsoft Access через ADO. Таблица состоит из трех полей, названных Account, Name и Balance (код счета, имя владельца и сумма денег на счете).

Процесс создания компонент в ATL состоит из трех этапов:

Для создания модуля в Developer Studio существует мастер ATL COM AppWizard.

  • Выберите пункт меню File -> New.
  • В качестве проекта выберите ‘ATL COM AppWizard’. Введите имя проекта — ‘AdoServer’ и нажмите ‘OK’.
  • Выберите тип модуля ‘Dynamic Link Library’, нажмите ‘Finish’.

(b) Добавление компонента к модулю

Для добавления компонента воспользуемся мастером ‘ATL Object Wizard’. Для достижения цели придерживаемся следующих шагов:

  • Выберите пункт меню ‘Insert | New ATL Object’. На экране появится мастер ‘ATL Object Wizard’
  • Выберите категорию объекта — ‘Simple Object’ и нажмите ‘Next’.
  • На экране появится диалог ‘ATL Object Wizard Properties’.
  • В качестве краткого имени (Short Name) наберите ‘Customer’. Все остальные поля заполнятся автоматически. Нажмите OK.

(c) Добавление методов компонента

  • Компонент, созданный только что созданный нами, не содержит никакой функциональности. Для придания объекту функциональности определим пять методов, AddRecord( ) , UpdateRecord( ) , DeleteRecord( ) , Getrsetbyid( ) и Getrsetbysort( ) . Перед этим добавим две функции в заголовочный файл ‘Customer.h’:

HRESULT FinalConstruct( )
<
HRESULT hr ;
CoInitialize ( NULL ) ;
hr = m_pconnection.CreateInstance( __uuidof ( Connection ) ) ;
hr =m_pconnection->Open(_T(«Prov > Source=d:\\table1.mdb»),»»,»»,adOpenUnspecified ) ;
return S_OK ;
>

HRESULT FinalRelease( )
<
CoUninitialize( ) ;
HRESULT hr = m_pconnection->Close( ) ;
>

Функция FinalConstruct( ) вызывается перед созданием объекта проектируемого нами компонента. В этой функции происходит инициализация библиотеки COM, создается объект типа Connection и открывается источник данных. В функции FinalRelease( ) мы делаем обратное: библиотека COM деинициализируется и закрывается соединение с источником данных. Для работы этих двух функций в класс CCustomer, в раздел private необходимо добавить переменную m_pconnection типа _ConnectionPtr .

  • Переключитесь на закладку определения класса (Class View tab). Выберите интерфейс ICustomer и нажмите правую кнопку мыши. Из появившегося меню выберите ‘Add Method’.
  • В появившемся диалоге ‘Add Method to Interface’ укажите имя метода ‘AddRecord’ и заполните поле ввода параметров следующей строкой:

[in] int id, [in] BSTR name, [in] int balance

  • Нажмите ‘OK’.
  • Подобным образом добавьте остальные методы в файл IDL.

HRESULT DeleteRecord ( [in] int id ) ;
HRESULT UpdateRecord ( [in] int id, [in] BSTR name, [in] int balance ) ;
HRESULT Getrsetbyid ( [in] int accno, [out,retval] IDispatch ** p ) ;
HRESULT Getrsetbysort ( [in] int no, [out,retval] IDispatch ** p );

  • Добавление метода AddRecord( ) генерирует описание следующей функции в файле ‘Customer.cpp’:

STDMETHODIMP CCustomer::AddRecord ( int id, BSTR name, int balance)
<
// TODO: Add your implementation code here
return S_OK ;
>

  • Добавьте следующий фрагмент кода в метод AddRecord( ) :

_RecordsetPtr recset ;
HRESULT hr ;
CString query ;
query.Format ( «SELECT * FROM bank WHERE id IS NULL» ) ;
CComVariant vNull ;
vNull.vt = VT_ERROR ;
vNull.scode = DISP_E_PARAMNOTFOUND ;
hr = recset.CreateInstance ( __uuidof ( Recordset ) ) ;
if ( SUCCEEDED ( hr ) )
<
recset -> PutRefActiveConnection ( m_pconnection ) ;
hr = recset -> Open ( query.operator LPCTSTR( ), vNull,
adOpenForwardOnly, adLockOptimistic, adCmdText );
if ( SUCCEEDED ( hr ) )
<
COleSafeArray fieldlist ;
fieldlist.CreateOneDim ( VT_VARIANT, 3 ) ;
long arrayindex[3] = < 0, 1, 2 >;
CComVariant f1 ( «id» ) ;
CComVariant f2 ( «Name» ) ;
CComVariant f3 ( «Balance» ) ;
fieldlist.PutElement ( &arrayindex[0], &f1 ) ;
fieldlist.PutElement ( &arrayindex[1], &f2 ) ;
fieldlist.PutElement ( &arrayindex[2], &f3 ) ;
COleSafeArray valuelist ;
valuelist.CreateOneDim ( VT_VARIANT, 3 ) ;
CComVariant v1 ( id ) ;
CComVariant v2 ( name ) ;
CComVariant v3 ( balance ) ;
valuelist.PutElement ( &arrayindex[0], &v1 ) ;
valuelist.PutElement ( &arrayindex[1], &v2 ) ;
valuelist.PutElement ( &arrayindex[2], &v3 ) ;
recset -> AddNew ( fieldlist, valuelist ) ;
recset -> Close( ) ;
>
>

Здесь мы создаем объект Recordset , подключаем его к уже созданному объекту Connection (это делается вызовом функции _RecordSet::PutRefActiveConnection( ) ) и добавляем запись вызовом функции AddNew( ) . Список полей и список значений этих полей, передаваемые в метод AddNew( ) , описаны как массивы значений типа CComVariant.

  • Метод DeleteRecord( ) реализуется следующим образом

STDMETHODIMP CCustomer::DeleteRecord ( int id )
<
AFX_MANAGE_STATE ( AfxGetStaticModuleState( ) )
_RecordsetPtr recset ;
HRESULT hr ;
CString query ;

query.Format ( «SELECT * FROM bank WHERE > CComVariant vNull ;
vNull.vt = VT_ERROR ;
vNull.scode = DISP_E_PARAMNOTFOUND ;
hr = recset.CreateInstance ( _uuidof ( Recordset ) ) ;
if ( SUCCEEDED ( hr ) )
<
recset->PutRefActiveConnection ( m_pconnection ) ;
hr = recset -> Open ( query.operator LPCTSTR( ), vNull,
adOpenForwardOnly, adLockOptimistic, adCmdText );
if ( !recset -> GetadoEOF( ) )
<
recset->Delete ( adAffectCurrent ) ;
recset->Close( ) ;
>
>
return S_OK ;
>

Функция аналогична AddRecord ( ) , за исключением строки запроса и того, что вместо метода AddNew( ) мы вызываем метод _RecordSet::Delete( ) .

  • Теперь добавим реализацию метода UpdateRecord( ) , содержащего следующий код:

STDMETHODIMP CCustomer::UpdateRecord ( int id, BSTR name, int balance )
<
AFX_MANAGE_STATE ( AfxGetStaticModuleState( ) )
_RecordsetPtr recset ;
HRESULT hr ;
CString query ;

query.Format ( «SELECT * FROM bank WHERE > CComVariant vNull ;
vNull.vt = VT_ERROR ;
vNull.scode = DISP_E_PARAMNOTFOUND ;
hr = recset.CreateInstance ( __uuidof ( Recordset ) ) ;
if ( SUCCEEDED ( hr ) )
<
recset -> PutRefActiveConnection ( m_pconnection ) ;
hr = recset -> Open ( query.operator LPCTSTR( ), vNull,
adOpenForwardOnly, adLockOptimistic, adCmdText );
if ( ! recset -> GetadoEOF( ) )
<
CComVariant f1 ( name ) ;
CComVariant f2 ( balance ) ;
recset -> PutCollect ( L»Name», &f1 ) ;
recset -> PutCollect ( L»Balance»,&f2 ) ;
recset -> Update ( vNull, vNull ) ;
recset -> Close( ) ;
>
>
return S_OK ;
>

  • Теперь нам нужен метод, который будет искать в таблице указанную запись. Вот как он может выглядеть:

STDMETHODIMP Ccustomer :: Getrsetbyid ( int accno,IDispatch **p )
<
AFX_MANAGE_STATE ( AfxGetStaticModuleState( ) )
_RecordsetPtr recset ;
CComVariant v ( 0L ) ;
CString query ;

query.Format ( «SELECT * FROM bank where > recset = m_pconnection -> Execute ( query.operator LPCTSTR( ), &v,
adOptionUnspecified ) ;
*p = ( IDispatch * ) recset ;
recset -> AddRef( ) ;
return S_OK ;
>

Так как мы не меняем извлеченную запись, запрос выполняется несколько по-другому, чем в предыдущих случаях. Мы просто получаем набор записей вызовом метода _Connection::Execute( ) . Заметим, что в данном случае необходимо вызвать метод AddRef( ) , т.к. мы знаем, что есть клиент, использующий полученный набор записей. Если бы мы этого не сделали, набор записей был бы уничтожен еще до его использования клиентским приложением. Итак, мы подошли к реализации последнего метода, позволяющего отсортировать набор записей, получаемый из источника данных. Вот исходный код этого метода:

STDMETHODIMP CCustomer::Getrsetbysort ( int no, IDispatch **p )
<
AFX_MANAGE_STATE ( AfxGetStaticModuleState( ) )
_RecordsetPtr recset ;
CString query ;
CComVariant v ( 0L ) ;

if ( no == 0 )
query.Format ( «SELECT * FROM bank order by id» ) ;
else
query.Format ( «SELECT * FROM bank order by Name» ) ;
recset = m_pconnection -> Execute (
query.operator LPCTSTR( ), &v, adOptionUnspecified ) ;
*p = ( Idispatch * ) recset ;
recset->AddRef( ) ;
return S_OK;
>

Эта функция подобна Getrsetbyid( ) , работа которой была была объяснена чуть выше. Здесь мы получаем различным образом отстортированный нобор записей в зависимости от переданного в функцию идентификатора.

  • В файл ‘stdafx.h’ необходимо добавить следующие операторы:

#include
#import «C:\Program Files\CommonFiles\System\ado\msado15.dll»
no_namespace rename ( «EOF», «adoEOF» )

Теперь полученный компонент можно откомпилировать. Посмотрим, как использовать компонент на клиентской стороне. В настоящий момент мы знаем, как строятся компоненты ADO, получающие записи из источника данных (т.е. «серверные» компоненты). Напишем реализацию клиента, использующего методы, которые мы только что описали.

Для того, чтобы написать COM-клиента с использованием MFC, нужно проделать следующее:

  • Создать исполняемое диалоговое приложение с помощью AppWizard.
  • Добавить элементы управления, например, как показано на рисунке 1.

В дополнение к набору элементов, показанных на рисунке 1 добавьте элемент просмотра списка (list view). Этот список будет заполняться, если пользователь нажмет кнопку ‘List’.

  • Используя ClassWizard добавьте три перменные m_id , m_name и m_bal типа integer, string и integer соответственно — они будут содержать значения полей ввода.
  • Аналогично создайте переменные m_list и m_rad типа CListCtrl и CButton для элемента списка и радиокнопки.
  • Добавьте переменные m_hide , m_commit и m_search , все типа CButton , для кнопок ‘Hide’, ‘Commit’ и ‘Search’ соответственно.
  • Также на закладке Class view создайте следующие переменные в заголовочный файл ‘AdoClientDlg.h’:

  • Импортируйте библиотеку типов (Type Library) сервера в клиентское приложение. Это делается занесением следующих строк в файл ‘StdAfx.h’.

# include
# include «atlbase.h»
# import «C:\Program Files\Common Files\System\ado\msado15.dll» no_namespace rename ( «EOF», «adoEOF» )
# import «..\AdoServer\AdoServer.tlb» using namespace ADOSERVERLib ;

  • Добавьте указатель на интерфейс cust типа ICustomer * в файл ‘CAdoClientDlg.h’.
  • В функцию инициализации диалога OnInitDialog( ) добавьте следующие код:

BOOL CAdoClientDlg::OnInitDialog( )
<
// AppWizard generated code
// TODO: Add extra initialization here
CoInitialize ( NULL ) ;
CLSID clsid ;
HRESULT hr ;
hr = CLSIDFromProgID( OLESTR («AdoServer.Customer» ), &clsid ) ;
hr = CoCreateInstance ( clsid, NULL, CLSCTX_ALL, __uuidof ( ICustomer ), (void **) &cust ) ;
acc = ( CEdit * ) GetDlgItem ( IDC_EDIT1 ) ;
name = ( CEdit * ) GetDlgItem ( IDC_EDIT2 ) ;
bal = ( CEdit* ) GetDlgItem ( IDC_EDIT3) ;

// insert columns in the list view control
m_list.InsertColumn ( 0,»ID»,LVCFMT_LEFT,100 ) ;
m_list.InsertColumn ( 1,»Name»,LVCFMT_LEFT,100 ) ;
m_list.InsertColumn ( 2,»Balance»,LVCFMT_LEFT,100 ) ;

  • Создайте обработчики для шести кнопок (Add, Delete, Update, Commit, List и Hide):

void CAdoClientDlg::OnAdd( )
<
acc -> EnableWindow ( TRUE ) ;
name -> EnableWindow ( TRUE ) ;
bal -> EnableWindow ( TRUE ) ;
m_commit.EnableWindow ( TRUE ) ;
m_oper = 1 ;
>

void CAdoClientDlg::OnDelete( )
<
acc -> EnableWindow ( TRUE ) ;
m_search.EnableWindow ( TRUE ) ;
m_oper = 3 ;
>

void CAdoClientDlg::OnUpdate( )
<
acc -> EnableWindow ( TRUE ) ;
m_search.EnableWindow ( TRUE ) ;
m_oper = 2 ;
>

void CAdoClientDlg::OnList( )
<
SetWindowPos ( &wndTop, 50, 50, 400, 390,
SWP_SHOWWINDOW ) ;
m_hide.ShowWindow ( SW_SHOW ) ;
m_list.DeleteAllItems( ) ;
UpdateData ( TRUE ) ;
CComVariant custaccno ;
CComVariant custname ;
CComVariant custbal ;
CString name,acc,bal ;
int i = 0 ;
_RecordsetPtr recset ;

recset = ( _RecordsetPtr ) cust -> Getrsetbysort ( m_rad1 ) ;
while ( !recset -> adoEOF )
<
custaccno = recset -> GetCollect ( L»id» ) ;
acc.Format ( «%d», custaccno.iVal ) ;
m_list.InsertItem ( i, acc, i ) ;
custname = recset -> GetCollect ( L»Name» ) ;
name = custname.bstrVal ;
m_list.SetItemText ( i, 1, name ) ;
custbal = recset -> GetCollect ( L»Balance» ) ;
bal.Format ( «%d», custbal.iVal ) ;
m_list.SetItemText ( i, 2, bal ) ;
recset -> MoveNext( ) ;
i++ ;
>
recset->Close( ) ;
>

void CAdoClientDlg::OnCommit( )
<
UpdateData ( TRUE ) ;
switch ( m_oper )
<
case 1:
cust -> AddRecord ( m_id, _bstr_t ( m_name ), m_bal ) ;
break ;
case 2:
cust -> UpdateRecord ( m_id, _bstr_t ( m_name ), m_bal ) ;
break ;
case 3:
cust -> DeleteRecord ( m_id ) ;
break ;
>
m_ > m_name = «» ;
m_bal = 0 ;
acc -> EnableWindow ( FALSE ) ;
name -> EnableWindow ( FALSE ) ;
bal -> EnableWindow ( FALSE ) ;
m_commit.EnableWindow ( FALSE ) ;
m_search.EnableWindow ( FALSE ) ;
UpdateData ( FALSE ) ;
>

void CAdoClientDlg::OnSearch( )
<
UpdateData(TRUE) ;
CComVariant custaccno ;
CComVariant custname ;
CComVariant custbal ;
_RecordsetPtr recset ;

recset = ( _RecordsetPtr ) cust -> Getrsetbyid ( m_id ) ;
if ( ! recset -> adoEOF )
<
custaccno = recset -> GetCollect ( L»id» ) ;
m_ > custname = recset -> GetCollect ( L»Name» ) ;
m_name = custname.bstrVal ;
custbal = recset -> GetCollect ( L»Balance» ) ;
m_bal = custbal.iVal ;
recset -> Close( ) ;
UpdateData ( FALSE ) ;
name -> EnableWindow ( TRUE ) ;
bal -> EnableWindow ( TRUE ) ;
m_commit.EnableWindow ( TRUE ) ;
>
else
MessageBox ( «Record not found» ) ;
>

  • Деинициализируйте библиотеку COM, вызвав CoUninitialize( ) в конце функции InitInstance( ) :

BOOL CAdoClientApp::InitInstance( )
<
// wizard generate code
CoUninitialize( ) ;
return FALSE;
>

На этом заканчивается написание клиентской части приложения. Теперь можно откомпилировать и запустить на выполнение клиента и проверить на практике, как происходит его взаимодействие с серверным компонентом ADO.

Опыт использования ADO для доступа к базам данных форматов MS Access, xBase и Paradox

Данная статья не является каким-либо учебным пособием, а просто попыткой обобщить некий опыт, полученный в течение некоторого времени при использовании ADO.

Подвигло меня на написание этой статьи то обстоятельство, что когда я приступал к этой работе (я имею в виду использование ADO), я размещал свои вопросы во многих конференциях, а ответов на них не получено до сих пор и, более того, эти же вопросы стали задаваться по новой, а ответов на них как не было, так и нет. На некоторые из них я отвечал, а потом подумал, что не все будут просматривать конференцию целиком, да и когда все сведено в одном месте оно и лучше. Кроме того, толковой литературы по использованию ADO практически нет никакой. Например, мне не удалось найти в солидных по объему книгах г-на Архангельского необходимую мне информацию. Или еще пример — Microsoft Press ‘Справочник по OLE DB’. Здесь другой уклон — информации много, слишком много, а примеров никаких (но это вообще проблема справок от Microsoft — написано много, а примеров использования почти нет).

Надеюсь, что те сведения, которые я приведу здесь, помогут коллегам по цеху в решении его задач

Причины перехода от BDE к ADO

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

Итак, для хранения атрибутивной информации был выбран формат MS Access, который имеет то обстоятельство, что все таблицы хранятся в одном файле (в отличие от Paradox и Dbase) и не требует при этом запущенного сервера, как, к примеру, Interbase. Необходима также связь с файлами форматов dbf и db для загрузки/выгрузки данных в/из БД. Для написания программы мы используем Delphi 4, а для подключения к файлам БД использовалась BDE. И все это было отлично, но вот появились два важных обстоятельства:

  • Вышел MS Access 2000. BDE отказывается работать с этим форматом. Как мне удалось найти ответ после долгих поисков на сайте Inprise — Inprise не знает как производить коннект к этому формату. Цитата: ‘Для доступа к данным MS Access мы используем DAO 2.5, который не может работать с форматом MS Access 2000. Если Вам необходим доступ к БД формата MS Access 2000, используйте, пожалуйста, компоненты ADO Delphi 5. По нашей (возможно неверной) информации причина здесь в отсутствии официальной документации от Microsoft.
  • Была найдена интересная особенность поведения BLOB потоков под управлением Windows NT 4. Допустим, нам необходим доступ к BLOB полям таблиц в БД формата MS Access 97. Как произвести подключение через BDE к MS Access 97 я говорить не буду, т.к. многие знают, а кто не знает, тот легко найдет эту информацию. Итак, подключение произведено. Отлично. Вот фрагмент программы:

Казалось бы — абсолютно тривиальный код. НО! Строка, где производится чтение из потока, вызывает исключительную ситуацию — ‘External error — EEFFACE’. И в исходных текстах VCL от Delphi 5 мы находим потрясающее объяснение — это, оказывается, ‘C++ Exception’. Интересно, а при чем тут C++? Единственный ответ, какой я знаю, — Delphi написана на C++.

Плюс ко всему, если вы запускаете эту программу из-под Delphi — ошибка не возникает, а если запускаете ее прямо в Windows — ошибка будет непременно. Я дошел в своих поисках до вызовов прямых вызовов BDE API — вот там-то ошибка и возникает, так что я думаю тут очередная ошибка BDE, хотя я использовал на тот момент самую последнюю версию с сайта Inprise — BDE 5.11.

Так что, господа, если Вы используете нечто подобное в своих программах, то знайте, что под Windows NT 4.0/Windows 2000 Ваши программы работать не будут. Самое интересное, что компоненты из библиотеки VCL, которые используют подобный метод для получения данных (к примеру, TDBRichEdit) тоже не работают!

Итак, этих двух причин оказалось достаточно для нашей фирмы, чтобы начать переход от BDE к ADO.

ADO и файлы формата MS Access

—Учитель, почему ты обманул меня? Ты сказал, что Вейдер предал и убил моего отца, а теперь оказалось, что он и есть мой отец!

—Твой отец: Его соблазнила темная сторона силы. Он больше не был Анекином Скайукером и стал Дартом Вейдером. Поэтому хороший человек, который был твоим отцом, был уничтожен. Так что, то, что я тебе сказал, было правдой: с определенной точки зрения:

—С определенной точки зрения?

—Люк: ты вот увидишь сам: что очень многие истины зависят от нашей точки зрения.

К чему я привел эту цитату — в результате всей этой работы я пришел к выводу, что у нас, программистов, и у Microsoft разный взгляд на фразу ‘Обеспечивается доступ к данным’. Мы (ну или, по крайней мере, я) в этой фразе видим следующее содержание ‘обеспечивается доступ к данным для их просмотра и РЕДАКТИРОВАНИЯ (т.е. редактирование, удаление и добавление новых данных)’. Что имеет в виду Microsoft можно только догадываться, но явно, что без особых проблем достигается только просмотр данных. Кроме того, практически все примеры в литературе ограничиваются получением данных именно для просмотра, после чего следует несколько бодрых фраз и все заканчивается. Как говорится выше — разные точки зрения:

Итак, прежде всего, работа была ограничена условием разработки в Delphi 4. Причин этому много, но к этой статье это отношения не имеет. Просто — программа, разработанная в Delphi 4 должна работать через ADO. Поэтому приступили к поиску компонент, обеспечивающих такую работу. Нашли их довольно много, как платных, так и бесплатных. Все, что будет написано, одинаково и для всех вариантов и даже для Delphi5. Исключение составляет только работа с закладками в Delphi 5.

ADO была взята на тот момент самая последняя версия с сайта Microsoft — это ADO 2.6.

Итак, возьмем файл mdb формата MS Access 97. Его можно сделать с помощью хотя бы самого Access. И создадим там небольшую таблицу, к примеру, такую:

Введем туда какие-либо данные (абсолютно все равно какие). Только надо учесть, что в силу специфики работы у нас могут быть описания, которым пока объекты не соответствуют. Такая связка будет выполнена позже пользователем. Ну, попробуем вывести содержимое таблицы в DBGrid. Ага, получилось. Например, как на картинке:

Вроде как все нормально и доступ к данным мы получили.

А теперь давайте, вообразим себя пользователями и попробуем что-нибудь исправить или добавить. Например, добавим несколько пустых записей и попробуем внести туда данные. Добавляем. Нормально. Теперь внесем данные и нажмем POST. И что мы видим?

Ага. Интересно, а при чем тут ключ, если у нас на таблицу ключ не наложен? Пробуем добавить новую запись, удалить запись без Object_ID. Результат одинаков — все то же сообщение об ошибке. И что же делать? Запускаем MS Access, пробуем там, и видим, что там все отлично. Стало быть, что-то не так мы делаем с ADO. И тут мы вспоминаем, что когда мы создавали таблицу в MS Access, он предлагал создать ключевые поля для этой таблицы. А после долгих поисков в ADO SDK я нашел этому такое объяснение: ADO предполагает, что таблица будет в первой нормальной форме. Если кто не помнит главное требование первой формы — отсутствие повторяющихся записей.

В данном случае мы не можем создать ключ на то, что есть. Что же делать? И тут приходит на ум простое решение: добавим еще одно поле, чтобы каждая запись была однозначно определена (т.е. некий внутренний идентификатор). Чтобы не думать о содержимом этого нового поля, делаем совсем просто — пусть это будет автоинкрементное поле, и создадим на него первичный ключ. Отлично! Делаем — все работает. Пока мы не добавляем больше одной записи. Если мы их добавим подряд несколько, мы увидим очень интересную ситуацию как на картинке.

Что здесь интересного? А то, что содержимое Internal_ID для всех этих записей равно нулю, хотя это автоинкрементное поле! И Table.Refresh здесь не помогает! Только закрытие и последующее открытие таблицы приводит к тому, что мы видим то, что и ожидалось.

А пока мы не имеем правильных идентификаторов, наличие такого поля не дает ничего. Выше приведенные ошибки будут продолжать сыпаться как из рога изобилия. Но вот только закрывать — открывать таблицу каждый раз после добавления новой записи для того, чтобы автоинкрементное поле принимало правильные значения — это сильно. Так не пойдет. Вот так ADO, подумал я, а давай-ка попробуем MS Access 2000. И тут оказалось, что там все нормально работает: добавляем запись, делаем сохранение (Post) автоинкрементное поле тут же принимает правильное значение.

В результате я могу сделать только один вывод — Microsoft активно, всеми доступными средствами, пытается заставить пользователей переходить к своим новым продуктам.

А вот почему в Access все нормально работает — это загадка. Я думаю, что сам-то он пользуется какими-то своими методами, либо в процессе работы у него есть некий идентификатор записи типа только что придуманного нами.

Ну а чтобы пользователь не видел этого внутреннего идентификатора (он ведь нужен только нам) делаем это поле невидимым. Надеюсь, что все знают, что это делается через TField.Visible := FALSE.

Кто-нибудь может возразить: а зачем нам такой идентификатор, мы можем записи идентифицировать по каким-нибудь своим полям. Ради Бога! Но тут есть еще одна проблема и эта проблема называется закладки.

Проблемы закладок нет в Delphi 5, потому что там вокруг Bookmark сделан класс ими управляющий, а я имею в виду работу с закладками через ADO. Смотрим опять же в ADO SDK и видим там такое описание:

‘Recordset.Bookmark: Устанавливает или возвращает закладку, которая однозначно определяет текущую запись в Recordset. При создании или открытии объекта Recordset каждая из его записей получает уникальную закладку. Для того чтобы запомнить положение текущей записи, следует присвоить текущее значение свойства Bookmark переменной. Для быстрого возвращения к сохраненному в переменной указателю текущей записи в любое время после перехода на другую запись следует указать в значении свойства Bookmark объекта Recordset значение этой переменной’.

Казалось бы, какие проблемы? А вот какие: возвращаемое значение всегда одно и тоже для любой записи. И когда мы устанавливаем этот, с позволения сказать, Bookmark, ничего не происходит. И только наш внутренний идентификатор поможет в такой ситуации, кроме того, его значение всегда имеет смысл, даже после закрытия и повторного открытия таблицы, что, в общем-то, удобно.

После того как все заработало, я решил проверить скорость работы ADO. У нас может быть ситуации, когда в таблицу добавляется сразу большое количество записей, к примеру, 50-60 тысяч записей за раз. Так вот, когда использовалась BDE, такая операция занимала максимум 10 минут. Угадайте, чему стало равно это время при использовании ADO? Минимум 25 минут на той же самой машине. Если после этого мне будут говорить, что ADO быстрее BDE чуть ли не в 2 раза — позвольте мне с Вами не согласиться.

Итак, для нормальной работы мы должны иметь таблицы в первой нормальной форме, для этого делаем автоинкрементное поле с уникальным индексом. Кроме того, если мы можем добавлять больше одной записи за один раз и потом сразу возможно будем их редактировать, нам надо использовать файлы MS Access 2000.

ADO и файлы xBASE и Paradox

Итак, мы смогли наладить работу через ADO к файлам формата MS Access. Но ведь мы можем и должны использовать файлы xBase и Paradox в качестве обменных файлов.

Попробуем это сделать. Все примеры какие я видел в книгах работают одинаково — через ‘Microsoft OLE DB provider for ODBC’. А все редакторы, которые делают строку подключения, всегда показывают только mdb файлы в диалоге, в котором задается путь к файлу БД. Что-то тут нечисто, подумал я — а как же тот же самый Access это делает? Ведь явно не через ODBC, стало быть, есть какая-то хитрость.

После примерно недельных поисков в Интернете решение было найдено. Да, действительно можно использовать ‘Microsoft Jet 4.0 OLE DB Provider’. Чтобы не рассказывать долго, представим, что у нас на диске D в корне лежит файл Test.dbf формата dBase 5.0.

Строка коннекта для этого случая будет выглядеть так:

Самое интересное во всей это строке — секция ‘Extended Properties’.

Чтобы знать, что конкретно для разных форматов надо писать в Extended properties, загляните в реестр Windows на следующую ветку:

Там перечислены все поддерживаемые в данном случае форматы.

После опытов над форматом dbf оказалось, что все выше сказанное для формата mdb совершенно не относится к этому формату — и все требования про первую форму можно и не соблюдать! В общем, загадка природы.

А вот формат Paradox — это оказалась песня на меньшая, чем mdb. И вот почему — здесь все требования о первой форме таблицы в действии, но ведь мы не можем создавать таблицу, потом говорить пользователю ‘Слышь, мужик, а теперь метнулся, запустил Paradox и создал первичный ключ на эту таблицу. А потом нажмешь на ОК и мы продолжим’. Это несерьезно. Стало быть, этот ключ надо создавать нам самим.

Хорошо, запускаем справку по MS Jet SQL и ищем раздел создания индексов или первичных ключей. Находим следующее:

Все далее сказанное абсолютно одинаково для обоих вариантов.

Предположим, что наша таблица называется ExpTbl.db и поле, на которое мы хотим наложить первичный ключ, называется IntrernalID. Хорошо, подключаемся к таблице и задаем такую строку SQL для исполнения:

Запустим на выполнение. Ого, а что это мы видим? Вот те на — очередное сообщение об ошибке. При этом сообщение как всегда очень содержательное применительно к нашему случаю.

Неправильных символов нет, синтаксис правильный, длина названия ключа тоже нормальная. Я так думаю потому, что если выполнить это через BDE, все будет работать со свистом.

Вывод один — опять очередное требование ADO, которое сразу не поймешь. Ладно, запускаем он-лайн MS MSDN и делаем запрос на PARADOX. Видим что-то около 50 документов. И где-то в 35-36 документе я нашел ответ маленькими буковками внизу экрана! Сейчас я вам скажу в чем проблема — держитесь крепче: имя первичного ключа должно совпадать с названием таблицы, а имена индексов с именами полей. Неслабо.

Запускаем, смотрим — все отлично.


Чтобы никто больше мучился с этим делом, я хотел бы привести самые значащие ограничения для драйвера PARADOX, которые я нашел в MSDN:

  • Для того, чтобы Вы имели возможность производить действия по добавлению, удалению записей или редактированию данных в таблице, таблица должна иметь первичный ключ.
  • Первичный ключ должен быть определен для первых ‘n’ полей таблицы.
  • Вы не можете создавать для таблицы индексы, если для нее не определен первичный ключ.
  • Первый создаваемый для таблицы уникальный индекс будет создан как первичный ключ.
  • Первичный ключ может быть создан для таблицы только в том случае, если в ней нет ни одной записи.
  • Действия по добавлению или удаления полей в таблице должны быть произведены до того, как для нее создан первичный ключ.

Кстати, по моему опыту удалить однажды созданный первичный ключ для таблицы невозможно.

Итак, для работы через ADO с файлами xBase или Paradox, нам необходимо указывать нужный драйвер в секции Extended Properties и в секции Data Source только путь до файла. Для xBase на этом все трудности закончены, а вот для Paradox необходимо задание первичного ключа как для формата MS Access, при этом есть определенные ограничения при задании названий ключей, так же как и возможных индексов.

То, о чем речь пойдет далее уже не относится к организации работы с таблицами xBase и Paradox через ADO, а скорее упоминание об одном полезном опыте.

Для добавления данных в эти таблицы, мы можем вставлять их по одной (Table.Append (Insert); Table.Post), а можем воспользоваться вариантом SELECT : INTO, INSERT : INTO. Поговорим теперь именно о втором варианте работы.

Смотрим файл справки MS Jet SQL.

Ладно, пробуем. Пусть мы имеем в качестве источника данных mdb файл и хотим сохранить данные из таблицы SourceTable в таблицу формата Paradox 7.0 TestTable.db, расположенную в корне диска D:.

Нет, очередная ошибка. Вот, что мы видим.

Ага, хорошо, давайте попробуем указать таблицу в пути:

Получим очередное сообщение об ошибке.

Ну, в общем, желающие могут еще поэкспериментировать, а для остальных я скажу как делается:

Создавать таблицу до операции экспорта нет надобности — таблица будет создана автоматически, все поля будут созданы правильного типа. В получившейся таблице будут все данные из SourceTable. Единственная проблема — Вы не сможете больше редактировать данные в этой таблице, потому (см. выше) для этого необходим первичный ключ, а создать его для таблицы, в которой уже есть записи нельзя.

Самое потрясающее это название раздела MSDN, где я нашел этот ответ — ‘Как, используя ADO, открыть таблицу Paradox, защищенную паролем’. Как ЭТО имеет отношение к этому синтаксису SQL, я так и не понял, честно говоря.

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

При написании статьи использовались следующие материалы:

  • Материалы Королевства Delphi.
  • Справочные файлы Delphi 4 и Delphi 5.
  • Исходные коды VCL Delphi 4 и Delphi 5.
  • MS ADO SDK и примеры MS ADO SDK.
  • MS MSDN.
  • А.Я. Архангельский ‘Язык SQL в Delphi 5’.

VB 6.0: доступ к данным с помощью технологии ADO

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

Часть 1. ADO идет на смену DAO и RDO

DAO, ADO, RDO. Все это похоже на какую-то игру слов, где присутствует два ключевых понятия: данные и объекты. (Data Access Objects — объекты доступа к данным, ActiveX Data Objects — ActiveX-объекты работы с данными, Remote Data Objects — объекты удаленных данных.) На самом же деле речь здесь идет о разных технологиях доступа к данным (см. врезку «Сравнение ADO, DAO и RDO»), которые имеют не только разные внутренние механизмы, но и, что, может быть, гораздо важнее для прикладного программиста, разные перспективы на будущее.

DAO и RDO известны уже достаточно давно, и появление двух разных механизмов было связано с необходимостью оптимизации решения двух отдельных задач: доступа к локальным и удаленным базам данных соответственно. Однако естественное развитие вычислительных систем привело к необходимости создания единого механизма, который обеспечил бы единый подход при работе с БД различных классов.

В результате несколько лет назад Microsoft предложила в качестве единого интерфейса для доступа к локальным и удаленным данным новую технологию ADO, которая сегодня является частью архитектуры Microsoft Universal Data Access (MUDA) 1 .

ADO 2.0 и новшества VB 6.0

Основой MUDA является OLE DB — низкоуровневый программный COM-интерфейс доступа к данным, который представляет собой развитие идеологии ODBC. Однако если ODBC предназначен для работы с реляционными базами данных (Access, DBF, SQL и др.), то OLE DB предлагает единообразный метод доступа к данным, хранящимся в разных источниках информации, в том числе и в нереляционных БД (например, в папках систем электронной почты или в простых файлах), обеспечивая при этом поддержку работы с наборами данных и иерархическими наборами записей, неподключенными постоянно к сети.

Поставщиками таких данных (OLE DB Provider) могут быть любые источники (в том числе приложения), написанные в соответствии со спецификациями OLE DB. Так, доступ к базам данных ODBC выполняется с помощью OLE DB Provider for ODBC.

ADO представляет собой прикладной объектный интерфейс более высокого уровня, который упрощает доступ к средствам OLE DB разработчикам, использующим языки высокого уровня. В 1998 году Microsoft выпустила модернизированный вариант ADO 2.0, который был впервые включен в состав в Visual Studio 6.0, и его автономных средств, в том числе VB 6.0.

ADO 2.0 представляет собой набор объектов, краткое описание которых приведено в табл. 1. VB-разработчик может работать напрямую или с помощью специальных средств, включенных в пакет. В первую очередь это новые элементы управления, функционирующие на основе OLE DB: ADO Data (является примерным аналогом уже известных элементов управления Data и Remote Date), DataGrid (DBGrid), DataList (DBList) и DataCombo (DBCombo).

Кроме того, VB 6.0 включает два новых инструмента работы с базами данных на основе OLE DB: конструктор Data Environment для установления связи с базами данных и создания отчетов, а также окно Data View для просмотра баз данных. (Мы уже подробно рассматривали эти средства в статье «Использование конструктора VB 6.0 Data Environment», КомпьютерПресс № 2’99, с. 140-144.) Следует также отметить, что VB-программист может создавать собственные поставщики данных OLE DB с помощью модуля классов (мы предполагаем рассмотреть этот вопрос в будущем).

Для использования ADO в VB-приложении нужно установить ссылку к библиотеке Microsoft ActiveX Data Objects Library 2.0 с помощью команды Project|References. Обратите внимание, что возможности ADO 2.0 доступны и при работе в среде VB 5.0. Для этого нужно установить на компьютер комплект MS Data Access Components, который можно загрузить, в частности, с узла http://www.microsoft.com/data/download.htm. Однако вы не сможете использовать элементы управления VB 5.0 совместно с элементом управления ADO Data. Впрочем, при желании можно воспользоваться компонентами независимых разработчиков, в том числе свободно распространяемых (например, по адресу: http://www.isgsoft.com).

DAO, RDO, ADO. Что выбрать?

Итак, теперь VB 6.0 поддерживает три различные технологии работы с базами данных. Очевидно, что каждая технология имеет свои плюсы и минусы и выбор нужного инструмента определяется спецификой задачи, а также квалификацией и навыками разработчика. Мы уже не раз подчеркивали, что эффективность конкретного применения инструмента определяется не только (или даже не столько) его внутренним совершенством, но и умением программиста работать с ним.

Тем не менее стоит упомянуть о результатах тестирования производительности разных методов доступа к данным, приведенным в статье «VS 6.0 Benchmarks: New Features Don’t Impact Speed» в журнале VBPJ (табл. 2). Там говорится об исследовании скоростных характеристик разных средств, входящих в состав Visual Studio 6.0, а также VB 5, для различных режимов работы программ (графика, математические задачи, обработка строк и пр.), в том числе и при работе с базами данных.

По результатам тестирования при работе с удаленными данными быстродействие ADO и RDO примерно одинаково. Что же касается локальных баз данных, то скорость ADO в 3-5 раз ниже, чем у DAO. Это, конечно, не очень здорово, но следует учитывать, что универсальный механизм всегда уступает специализированным, имея в качестве преимущества упрощение процесса разработки. (Современный стиль разработки заключается именно в таких приоритетах: главное — сократить трудоемкость разработки, а уже потом думать о повышении эффективности приложений. Можно осуждать подобный прагматизм, но факт остается фактом.)

Более важным является другой момент: Microsoft объявила, что будет совершенствовать и обновлять только модель ADO (что соответствует общей стратегии корпорации на унификацию разных технологий на базе ActiveX), то есть DAO и RDO постепенно должны сойти со сцены.

Вывод из этого очевиден: если сейчас вы используете DAO или RDO для доступа к данным, то в конце концов вам, вероятно, придется совершить этот переход к ADO в новых разработках. Но когда это лучше сделать? С одной стороны, лучше раньше, чем позже. С другой — торопиться не надо. Здесь следует отметить еще два важных момента.

Многие VB-эксперты указывают на недостатки существующей сегодня версии ADO. Если не принимать во внимание снижение производительности 2 , то главный упрек заключается в наличии довольно большого числа программных ошибок. В связи с этим эксперты журнала VBPJ советуют разработчикам дождаться выхода ADO 2.5. Впрочем, классический принцип освоения новых технологий говорит о том, что их использование в реальных системах лучше начинать с версии 3.

Так что вопрос о том, когда переходить к ADO, решать вам, но готовиться к этому нужно уже сегодня.

Часть 2. Переход от DAO к ADO: это вполне реально

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

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

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

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

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

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

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

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

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

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

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

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

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

В этом и состоит характерное отличие 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. Примеры, приведенные в этой статье, являются лишь иллюстрацией наиболее типичных вопросов, которые следует решать при переводе программного кода. Выполнение такого преобразования требует больше, чем переработка кода вручную, — оно должно сопровождаться тщательным тестированием и использованием пошагового подхода. Прежде чем изменить всего одну строку кода, следует разработать стратегию всего преобразования (см. врезку «Разработка эффективной стратегии миграции»).

Технология ADO и средства доступа к реляционным базам данных

Рубрика: Информационные технологии

Дата публикации: 04.06.2015 2015-06-04

Статья просмотрена: 986 раз

Библиографическое описание:

Абилдаева Г. Б., Жанкоразова Н. Н., Жанадил М. О. Технология ADO и средства доступа к реляционным базам данных // Молодой ученый. — 2015. — №11. — С. 156-158. — URL https://moluch.ru/archive/91/18279/ (дата обращения: 13.11.2020).

Коротко на вопрос «Что такое ADO?» можно ответить так: это основная технология доступа к данным, не только реляционные базы данных для платформы.NET. Более конкретно — это набор объектов, при помощи которых программист может осуществить подключение к серверу баз данных, выборку данных и/или их модификацию.

Многие программисты, работающие с базами данных на платформах Microsoft, могли оценить простоту и удобство технологии ADO — ActiveX Data Objects. Интуитивно-понятный интерфейс и логичный набор объектов вместе с простотой программирования заслуженно получили признание программистов. Несмотря на это, вместе с новой платформой.NET Microsoft представляет и новое поколение средств доступа к базам данных — ADO.NET. Cтремительное развитие веб приложений вызвало необходимость пересмотреть методы работы с источниками данных, лучше адаптировать их к специфики приложений. Непредсказуемый рост числа клиентов интернет сайтов заставляет разработчиков переходить от клиентсерверной к three-tier архитектуре, что часто порождает непреодолимые проблемы. Базы данных не способны поддерживать неограниченное число активных соединений, ограничивая доступность сайта и принося убытки. Брандмауэры могут препятствовать передаче двоичных данных между узлами. ADO.NET призвано решить эти и другие проблемы и вместе с тем сохранить удобство и простоту программирования.

ADO была разработана для архитектуры клиент-сервер. Эта архитектура в течение ряда лет была достаточно прогрессивной, если учесть, что пришла она на смену архитектуре файл-сервер. Потом все нарастающая сложность систем обработки данных потребовала качественного изменения архитектуры: кроме двух уровней клиент и сервер баз данных появляются дополнительные уровни серверы, реализующие бизнес-логику приложений. До сих пор, правда, ни одна из разработанных для этой цели архитектур (в частности, DCOM и CORBA) не добились впечатляющих успехов в этом направлении, и на сегодняшний момент мне известно, пожалуй, больше вирусов, использующих их слабости, чем реально работающих продуктов на их основе..NET в целом и ADO.NET в частности очередная попытка навести порядок в сегменте многоуровневых приложений и сделать их разработку относительно простым и приятным занятием. Что из этого выйдет, судить пока рано, но, на мой взгляд, перспективы неплохи [1].

Поскольку ADO.NET ориентирована на разработку многоуровневых приложений корпоративного масштаба, это отложило неизбежный отпечаток на способы взаимодействия клиента с сервером. Если основной сценарий работы клиента в ADO начинается с создания соединения, которое потом удерживается открытым весь сеанс, то ADO.NET гораздо самостоятельнее в этом отношении. Вполне допустимым является сценарий, когда клиент устанавливает соединение, получает необходимые данные, закрывает соединение, длительное время обрабатывает данные, после чего вновь устанавливает соединение для передачи измененных данных обратно на сервер.

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

MSDN божится, что при разработке ADO.NET преследовалась цель сделать новую платформу как можно более совместимой с прежней, так что разработчики особой разницы не заметят.

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

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

Опыт разработчиков показал, что приложения с постоянным соединением с источником данных чрезвычайно трудно поддаются масштабированию.

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

Следует признать, что новая технология иногда все же проигрывает традиционной. Для этих случаев рекомендовано (не только мною, но и Microsoft) использовать ADO.

Хранение данных в объектах DataSet. При работе с базой данных нам чаще всего приходится работать не с одной, а несколькими записями. Более того, данные эти могут собираться из различных таблиц. В разъединенной модели доступа к базе данных не имеет смысла соединяться и источником данных при каждом обращении. Исходя из этого, представляется логичным хранить несколько строк и обращаться к ним при необходимости. Для этих целей и используется DataSet [2].

DataSet представляет собой, по сути, упрощенную реляционную базу данных и может выполнять наиболее типичные для таких баз данных операции. Теперь, в отличие от Recordset мы можем хранить в одном DataSet сразу несколько таблиц, связи между ними, выполнять операции выборки, удаления и обновления данных. Безусловно, разъединенная модель не позволяет постоянно отслеживать изменения в базе данных, производимые другими пользователями. Это может привести к ошибкам в таких приложениях, где информация должна обновляться каждый момент — заказ билетов или продажа ценных бумаг. Однако в любую секунду может быть получена свежая информация из базы данных через вызов метода FillDataSet. Таким образом, DataSet остается чрезвычайно удобным для самого широкого класса приложений: когда необходимо получить данные из базы и как-либо обработать их.

ADO.NET поддерживает два типа источников данных — SQL Managed Provider и ADO Managed Provider. SQL Managed Provider применяется для работы с Microsoft SQL Server 7.0 и выше, ADO Managed Provider — для всех остальных баз данных.

SQL Managed Provider — работает по специальному протоколу, называемому TabularData Stream (TDS) и не использует ни ADO, ни ODBC, ни какую-либо еще технологию. Ориентированный специально на MS SQL Server, протокол позволяет увеличить скорость передачи данных и тем самым повысить общую производительность приложения.

ADO Managed Provider — предназначен для работы с произвольной базой данных. Однако за счет универсальности есть проигрыш по сравнению с SQL Server Provider, так что при работе с SQL Server рекомендовано использовать специализированные классы. В данном обзоре мы коснемся ADO Managed Provider лишь мельком, указав только существующие незначительные различия, так как наиболее употребимой базой данных представляется SQL Server 7.0 или 2000, а разница заключается, в основном, в именовании.


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

ADO.NET DataSet — расположенное в оперативной памяти представление данных, обеспечивающее согласованную реляционную программную модель независимо от источника данных. DataSet представляет полный набор данных, включая таблицы, содержащие, упорядочивающие и ограничивающие данные, а также связи между таблицами.

Существует несколько способов работы с DataSet, которые могут применяться отдельно или в сочетании. Можно выполнить следующие действия:

— Программно создать DataTable, DataRelation и Constraint внутри DataSet и заполнить таблицы данными.

— Заполнить DataSet таблицами данных из существующего реляционного источника данных с помощью DataAdapter.

— Загрузить и сохранить содержимое DataSet с помощью XML-кода.

Строго типизированный DataSet также можно передавать с помощью веб-службы с поддержкой XML-кода. Конструкция DataSet делает его идеальным для передачи данных с помощью веб-служб с поддержкой XML-кода.

Объектная модель DataSet. Методы и объекты DataSet согласованы с методами и объектами модели реляционной базы данных.

Объект DataSet также может сохранять и повторно загружать свое содержимое в виде XML, а свою схему — в виде схемы XSD.

Класс DataTableCollection. Объект ADO.NET DataSet содержит коллекцию, содержащую ноль или более таблиц, представленных объектами DataTable. Коллекция DataTableCollection содержит все объекты DataTable в объекте DataSet.

Объект DataTable определяется в пространстве имен System.Data и представляет собой одну таблицу, находящуюся в оперативной памяти. Он содержит коллекцию столбцов, представленных объектом DataColumnCollection, и ограничений, представленных объектом ConstraintCollection, которые вместе определяют схему таблицы. Объект DataTable также содержит коллекцию строк, представленных объектом DataRowCollection, содержащим данные в таблице. Вместе со своим текущим состоянием объект DataRow сохраняет обе свои версии (текущую и исходную), чтобы определить изменения значений, хранимых в строке.

Класс DataView. DataView позволяет создавать различные представления данных, которые хранятся в DataTable. Эта возможность часто используется в приложениях связывания данных. С помощью объекта DataView можно представлять данные в таблице с различными порядками сортировки, а также фильтровать данные по состоянию строки или на основе критерия фильтра.

Класс DataRelationCollection .Объект DataSet содержит связи в своем объекте DataRelationCollection. Связь, представленная объектом DataRelation, связывает строки в одном объекте DataTable со строками в другом объекте DataTable. Связь аналогична пути соединения, который может существовать между столбцами первичного и внешнего ключей реляционной базы данных. Объект DataRelation определяет совпадающие столбцы в двух таблицах объекта DataSet.

Связи позволяют перемещаться в объекте DataSet от одной таблицы к другой. Важными элементами объекта DataRelation являются имя связи, имена связанных таблиц и связанные столбцы в каждой таблице. Связи могут быть построены с более чем одним столбцом для каждой таблицы путем указания массива объектов DataColumn в качестве ключевых столбцов. При добавлении связи к объекту DataRelationCollection дополнительно можно добавить UniqueKeyConstraint и ForeignKeyConstraint, чтобы обеспечить ограничения целостности в случае изменений значений связанных столбцов.

Использование объектов подключения и набора записей ADO

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

1. Создайте новый проект командой File > New Project. Выберите в диалоговом окне New Project значок Standard EXE и нажмите кнопку ОК.

2. Задайте свойству Name проекта значение ADORecordset.

3. Задайте свойству Name формы Form1 значение frmMain, а свойству Caption — зна-чениеРабота с наборами записей ADO.

4. Создайте список на форме frmMain и задайте его свойству Name значение 1st Authors.

Как упоминалось ранее, элемент данных ADO является элементом ActiveX. Его можно перетащить на форму, как и любой другой элемент. Объекты подключения и набора записей являются DLL-библиотеками (библиотеками динамической компоновки) Active, и доступ к ним осуществляется только с помощью ссылки на библиотеку типов.

ПРИМЕЧАНИЕБиблиотека типов содержит полное описание компонента: свойства, методы, события и типы данных.

5. Выполните в Visual Basic команду Project > References, чтобы открыть диалоговое окно References.

6. Создайте ссылку на библиотеку типов ADO. Для этого следует установить флажок рядом со строкой Microsoft ActiveX Data Objects 2.0 (рис. 8.19).

Puc. 8.19. Создание ссылки на библиотеку типов ADO

7. Нажмите кнопку OK, чтобы создать ссылку на библиотеку и закрыть диалоговое окно References. Теперь вы можете использовать объекты подключения и набора записей ADO в своей программе.

8. Добавьте следующие объявления в секцию (General)(Declarations) формы:

Private cn As ADODB.Connection

Private rs As ADODB.Recordset

9. Вставьте следующий фрагмент в процедуру события Form_Load:

Private Sub Form_Load()

Dim cmd As String

Dim sql As String

Dim cn As ADODB.Connection

Dim rs As ADODB.Recordset

‘Создать строку подключения

«C:\Program Files\Microsoft Visual Studio» & _

‘Установить соединение с базой данных

Set cn = New ADODB.Connection

sql = «select * from authors»

‘ Открыть набор записей

Set rs.= New ADODB.Recordset

.Open sql, cn, adOpenForwardOnly, adLockReadOnly

Do While Not rs.EOF

‘ Включить автора в список

‘ Перейти к следующей записи

‘ Закрыть набор записей .

Set rs = Nothing

‘уничтожить объект подключения

Set cn = Nothing

10.Сохраните и запустите проект.

Программа просто обращается к базе данных Biblio.mdb и заполняет список именами авторов из таблицы Authors. Наверное, вам покажется, что для такой простой задачи программа получилась слишком большой, но если как следует разобраться, вы поймете, что в ней нет ничего сложного.

В начале программы объявляются две переменные, cmd и sql. В переменной cmd, будет храниться строка подключения ADO, используемая для подключения к базе данных. Переменная sql предназначена для текста SQL-запроса. Следующий фрагмент создает строку для подключения к Biblio.mdb c помощью нового провайдера OLEDB (указывается после конструкции Prov >

Следующий шаг — фактическое подключение к базе данных. Для этого мы создаем объект ADO.Connection и затем устанавливаем его свойство ConnectionString равным cmd. После этого выполняется метод . Open данного объекта. Метод берет данные, находящиеся в свойстве ConnectionString, и использует их для подключения к базе.

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

sql = «select * from authors»

Не вдаваясь в подробности SQL, этот запрос означает следующее: «выбрать все (*) записи из таблицы с именем Authors». Именно это и было сделано в нашем примере.

У нас имеется запрос, по которому можно создать набор записей. Новый объект набора записей создается следующим образом:

Set rs = New ADODB.Recordset

Только что созданный набор не содержит никакой информации. В блоке With мы приказываем ADO открыть набор командой

.Open sql, cn, adOpenForwardOnly, adLockReadOnly

Вероятно, вы обратили внимание на параметры, необходимые для открытия набора записей. В первом параметре хранится SQL-запрос для данного набора. Второй параметр, cn, говорит о том, что для подключения к базе данных набор должен использовать объект подключения cn. Можно провести аналогию между набором записей и машиной: подключение — дорога, по которой машина добирается к данным. Следующий параметр сообщает ADO, какой тип курсора базы данных должен использоваться для набора. В следующей таблице перечислены возможные варианты курсоров с краткими описаниями.

Тип курсора Описание
adOpenForwardOnly Курсор этого типа может использоваться лишь для последовательного перебора записей в одном направлении. Перебор в обратном направлении и произвольные переходы не разрешаются. Тем не менее этот вариант отличается быстротой и пригодится в случае, если вам потребовалось быстро заполнить список или комбинированное поле
Ad0penKeyset Оптимальный тип курсора для больших наборов. Вы не получаете сообщений об изменениях в данных, которые могут повлиять на ваш набор записей
Ad0penDynamic Курсор позволяет отслеживать все изменения, вносимые другими пользователями в ваш набор записей. Он обладает наибольшими возможностями, но из-за этого работает медленнее всех остальных
AdOpenStatic Статический курсор удобен для небольших наборов

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

Тип блокировки Описание
aLockReadOnly Данный режим блокировки следует использовать лишь в том случае, если вы не собираетесь добавлять, обновлять или удалять записи из набора
AdLockPessimistic Запись блокируется в момент начала редактирования и остается заблокированной до его завершения или перемещения курсора к следующей записи
AdLockOptimistic Оптимистический режим: блокировка включается при вызове метода . Update для записи. В процессе редактирования запись остается незаблокированной и лишь временно блокируется на время сохранения изменений в базе
AdLockBatchOptimistic Режим позволяет выполнять оптимистическую блокировку при обновлении нескольких записей

Если все параметры были указаны верно, набор записей открывается и вы можете работать с его данными.

В следующем фрагменте программа в цикле перебирает все записи до тех пор, пока не будет найден признак конца файла (EOF). При перемещении курсора к очередной записи мы заносим данные из поля Author в список:

После занесения очередного имени в список мы переходим к следующей записи с помощью метода . MoveNext. Если позабыть об этом, цикл будет работать вечно, потому что признак конца файла никогда не будет достигнут. Наконец, после окончания работы все открытое нужно закрыть, а все созданное — уничтожить. Для этого следует вызвать метод .Close для объектов Recordset и Connection. Далее этим объектам присваивается Nothing для предотвращения утечек памяти в вашем приложении.

ВНИМАНИЕОбрабатывая записи набора в цикле, обязательно включайте в него метод . MoveNext. Если вы забудете это сделать (а это случается часто), ваша программа зациклится. Запишите оператор Do While. a потом — команду .MoveNext сразу же перед командой Loop, а уже потом вставляйте свой код обработки данных. Тем самым вы сводите вероятность ошибки к минимуму.

Добавление записей

Хотя в данном примере такая возможность не требовалась, в большинстве приложений в наборы добавляются новые записи. С объектами наборов записей ADO эта задача выполняется чрезвычайно просто. Для этого в программе следует вы-зватьметод .AddNew:

rs(«Author) = «Doe, John» rs(«Au_ >

Все очень просто. Когда вам требуется создать новую запись, вы вызываете метод .AddNew. Он создает пустую запись, в которую затем заносятся данные. Это можно сделать несколькими способами, включая следующие:

Rs(«Author») = «Doe, John»

Rs!Author = «Doe, John»

Rs.Fields(1) = «Doe, John»

Все они эквивалентны, и выбор зависит лишь от вашего личного вкуса. Лично я предпочитаю первый способ, потому что он выглядит наиболее очевидно. Я точно знаю, какое поле обновляется, а поскольку имя поля заключено в кавычки, оно может содержать пробелы.

После занесения данных в запись следует обновить набор, вызвав метод . Update.

Обновление записей

Процесс обновления записей напоминает процесс добавления, однако на этот раз вам не придется вызывать метод .AddNew. Достаточно переместить курсор базы данных к нужной записи, изменить данные и вызвать метод . Update. Например:

Rs(«Author») = «Brown, Steve»

ПРИМЕЧАНИЕЕсли вам приходилось работать с объектами DAO, возможно, вы привыкли вызывать метод . Edit для перехода к редактированию данных. Он не поддерживается объектами ADO.

Удаление записей

Удаление записей в ADO выполняется так же просто. Все, что от вас требуется -установить курсор базы данных на удаляемой записи и вызвать метод . Delete. Программа выглядит примерно так:

sql = «select *from authors where [Author] = ‘Brown, Steve»»

‘ Открыть набор записей

Set rs = New ADODB.Recordset

.Open sql, cn, adOpenForwardOnly, adLockReadOnly

If rs.RecordCount > 0 Then

‘ Закрыть набор записей

‘ Уничтожить объект набора записей

Set rs = Nothing

ПОДСКАЗКАПереходите на использование ADO, поскольку Microsoft развивает свои технологии работы с данными именно в этом направлении. Вы не только будете работать с последними технологическими новинками, но и сможете переносить свои приложения на другие источники данных с минимальными изменениями кода (или вообще без изменений).Более того, ADO даже позволяет организовать обмен данными между базой и Web-страницей!

Теперь вы умеете создавать базы данных Access и работать с ними различными способами. Навыки, описанные в этом уроке, помогут вам работать с базами данных в будущих приложениях. Хотя возможности новой версии Visual Data Manager заметно возросли, все же я рекомендовал бы приобрести Microsoft Access, если вы не сделали этого раньше. Access обладает многими возможностями, упрощающими создание базы данных даже по сравнению с описанным выше несложным процессом. А самое приятное — ваши базы данных останутся совместимыми с Visual Basic!

Научившись работать с файлами и базами данных, вы сможете взять данные из своего приложения и сохранить их для последующей загрузки или печати, а также воспользоваться ими для сохранения и выборки рабочих параметров приложения. Не жалейте времени на эксперименты с Visual Data Manager. Он обладает многими возможностями, не упоминавшимися в этом уроке (полное описание потребовало бы отдельной книги). Объединяя возможности Visual Basic по программированию и работе с базами данных, вы сможете создавать достаточно мощные приложения. Следующий урок посвящен третьему важному аспекту любого приложения — печати.

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Да какие ж вы математики, если запаролиться нормально не можете. 8427 — | 7331 — или читать все.

188.64.174.135 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.


Отключите adBlock!
и обновите страницу (F5)

очень нужно

Использование библиотеки ADO (Microsoft ActiveX Data Object) (стр. 1 )

Из за большого объема этот материал размещен на нескольких страницах:
1 2

Перейти на главную страничку сайта (список статей, файлы для скачивания)

ФОРУМ (здесь можно обсудить эту статью, а также любые проблемы программирования на различных макроязыках и в скриптовых средах)

Использование библиотеки ADO (Microsoft ActiveX Data Object)

Понятие о библиотеке ADO

Библиотека ADO (Microsoft ActiveX Data Object) служит для доступа к базам данных различных типов и предоставляет объектный программный интерфейс к интерфейсу OLE DB, который предлагается компанией Microsoft как альтернатива интерфейсу ODBC. Объектная модель ADO реализована на базе технологии COM (Component Object Model).

В середине 1990-х годов, с развитием и распространением технологии COM (Component Object Model), компания Microsoft объявила о постепенном переходе от ODBC к использованию новой технологии OLE DB. Однако OLE DB, по мнению самой компании Microsoft, является интерфейсом системного уровня, этот интерфейс должен использоваться системными программистами. Технология OLE DB является тяжеловесной, сложной и очень чувствительной к ошибкам. Она требует от программиста слишком многого. Работать с OLE DB слишком сложно. Чтобы облегчить работу с OLE DB, был создан дополнительный прикладной уровень, который получил название ADO (ActiveX Data Objects). Работать с ADO существенно проще, чем с OLE DB. Технология ADO предназначена для прикладных программистов.

На самом деле ADO является частью более крупномасштабной технологии под названием Microsoft Data Access Components (MDAC). Термин MDAC является общим обозначением для всех разработанных компанией Microsoft технологий, связанных с БД. К этому набору относятся ADO, OLE DB, ODBC и RDS (Remote Data Services). Часто приходится слышать, что люди используют термины MDAC и ADO как синонимы, однако это неправильно. На самом деле ADO является лишь одной из частей MDAC. Когда мы говорим о версиях ADO, мы имеем в виду версии MDAC. К основным версиям MDAC относятся версии 1.5, 2.0, 2.1, 2.5 и 2.6. Компания Microsoft распространяет MDAC в виде отдельного продукта. Этот продукт может быть загружен с веб-узла Microsoft бесплатно. Мало того, фактически его можно бесплатно включать в состав ваших собственных продуктов (существуют определенные ограничения, однако большинство разработчиков Delphi без каких-либо проблем удовлетворяют всем этим требованиям). Кроме того, MDAC входит в комплект поставки большинства продуктов Microsoft, имеющих отношение к базам данных. Обновление может быть выполнено вами, вашими пользователями или одним из устанавливаемых в системе приложений Microsoft. Подобное обновление фактически невозможно предотвратить, так как MDAC устанавливается в составе такого широко распространенного приложения, как Internet Explorer. К этому следует добавить, что компания Microsoft поддерживает лишь самую последнюю версию MDAC, а также версию, предшествующую самой последней. Исходя из всего этого, можно прийти к выводу: ваше приложение должно работать с самым свежим выпуском MDAC или с предшествующей ему версией.

Как разработчик ADO, вы должны регулярно просматривать страницы веб-узла Microsoft, посвященные MDAC. Для этого следует обратиться по адресу www. /data. Здесь вы сможете бесплатно загрузить самую свежую версию MDAC. Также рекомендуется загрузить MDAC SDK (13 Мбайт), если у вас еще нет этого пакета. На самом деле MDAC SDK входит в состав Platform SDK, так что, если у вас есть Platform SDK, значит, вы уже обладаете MDAC SDK. Пусть пакет MDAC SDK станет вашей библией. Вы должны загрузить его и регулярно обращаться к нему для получения необходимых сведений и ответов на любые вопросы, связанные с ADO. Если вы нуждаетесь в информации, связанной с MDAC, прежде всего вы должны обратиться к MDAC SDK.

Библиотека ADO может быть использована в любых средах, которые в состоянии выступить в роли OLE-клиента, например, в MS Office (VBA), 1C:Предприятии, административных скриптах Windows (.vbs и. js) и т. д. Примеры кода в настоящей статье будут приводиться на языке VBScript для административных скриптов Windows. С помощью библиотеки ADO можно обратиться к огромному количеству типов баз данных, например, dBASE, Access, Excel, Oracle, Paradox, MS SQL Server, Sybase, текстовые файлы, FoxPro, Active Directory Service, Microsoft Jet, Interbase, Informix, PostgreSQL, MySQL и т. д., необходимо только наличие установленного соответствующего OLE-провайдера («драйвера» соответствующего типа базы данных, который устанавливается в систему как правило из дистрибутива этой же базы данных). Примеры кода в настоящей статье будут приводиться только для MS SQL Server, т. к. невозможно объять необъятное. Перечень свойств и методов ADO, приведённый в этой статье, не является исчерпывающим (в некоторых случаях и описание некоторых свойств и методов не является полным). Полное описание объектной модели библиотеки ADO вы можете получить в MSDN или в файле «ADO210.CHM», который входит в поставку MS Office. Однако материала данной статьи достаточно, чтобы начать работать с ADO.

Основными объектами библиотеки ADO являются объекты Connection, Command и Recordset.

Объект Connection

Объект Connection обеспечивает создание подключения к источнику данных и эквивалентен текущему сетевому соединению с сервером. Объект Connection предоставляет возможность настройки соединения перед его открытием, установки базы данных по умолчанию, установки и разрыва соединения с источником данных, задания настроек и выполнения команды с помощью метода Execute. Примечание: для выполнения команды можно использовать также метод Execute объекта Command, не прибегая к объекту Connection.

Объект Connection создаётся следующим образом:

Set objConn = CreateObject(«ADODB. Connection»)

После этого вы можете вызывать и использовать методы и свойства этого объекта для доступа к базам данных:

Содержит строку, определяющую версию библиотеки. Только чтение.

Определяет параметры подключения к источнику данных. Чтение и запись. Это строка, содержащая несколько параметров, разделённых точкой с запятой. Свойство ConnectionString автоматически получает значение, заданное в качестве одноимённого аргумента метода Open. Свойство ConnectionString доступно для записи только для закрытого соединения. Многочисленные примеры различных строк подключения для различных типов баз данных вы можете найти в Интернете или в документации к соответствующим программным продуктам.

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

Устанавливает или возвращает число секунд ожидания выполнения команды. Значение по умолчанию — 30. Чтение и запись. Используйте это свойство, если возникают проблемы из-за плотного сетевого трафика или загруженности сервера. Если время, указанное в CommandTimeout, истекает до завершения выполнения команды, происходит ошибка, и ADO отменяет команду. Если Вы установите свойство в ноль, ADO будет ждать бесконечно, пока команда не будет выполнена. Удостоверьтесь, что используемый провайдер поддерживает свойство CommandTimeout. Установка CommandTimeout объекта Connection никак не связана с установкой свойства CommandTimeout объекта Command.

Устанавливает или возвращает строковое значение, которое содержит имя используемого провайдера. По умолчанию — «MSDASQL». Провайдер может быть также установлен содержанием свойства ConnectionString или параметром метода Open. Определение провайдера в более чем одном месте может иметь непредсказуемые результаты.

Устанавливает или возвращает строковое значение, которое содержит заданную по умолчанию базу данных. Если есть заданная по умолчанию база данных, запросы SQL могут использовать «дисквалифицированный» синтаксис для обращения к объектам в этой базе данных. Чтобы обращаться к объектам из другой базы данных, вы должны «квалифицировать» имена объектов именем этой базы данных. При подключении провайдер записывает заданную по умолчанию базу данных в это свойство. Некоторые провайдеры разрешают только одну такую базу данных на одно подключение, и в этом случае вы не сможете изменить это свойство. Некоторые источники данных и провайдеры могут не поддерживать это свойство, генерируя ошибку или возвращая пустую строку.

Определяет расположение курсора, т. е. место, где выполняется работа с данными. Возможные значения:

    adUseNone(1) — курсор не используется (только для совместимости со старыми версиями). adUseServer(2) — курсор на стороне провайдера (по умолчанию). adUseClient(3) — курсор на стороне пользователя. Может предоставлять дополнительные возможности, которые отсутствуют на стороне провайдера.

Изменение свойства CursorLocation не имеет никакого эффекта при уже существующем подключении. Связанные объекты Recordset и курсоры, возвращённые методом Execute, наследуют эту установку. При открытом объекте Recordset это свойство доступно только для чтения.

Определяет режим доступа для изменения данных в сеансе. Возможные значения:

    adModeUnknown(0) — режим доступа не установлен или не может быть определён (по умолчанию). adModeRead(1) — режим только для чтения. adModeWrite(2) — режим только для записи. adModeReadWrite(3) — режим для чтения и записи. adModeShareDenyRead(4) — не разрешает открывать соединение на чтение другим пользователям. adModeShareDenyWrite(8) — не разрешает открывать соединение на запись другим пользователям. adModeShareExclusive(12) — не разрешает открывать соединение другим пользователям. adModeShareDenyNone(16) — разрешает открывать соединение с любым видом доступа другим пользователям.

Вы можете установить это свойство только тогда, когда объект Connection закрыт.

Содержит коллекцию объектов Error. Любая инструкция, использующая объекты ADO, может сгенерировать одну или более ошибок провайдера. Когда происходит ошибка, в эту коллекцию могут быть помещены один или более объектов Error. Если следующая подобная инструкция также сгенерирует ошибку, коллекция будет очищена и заполнена заново. Каждый объект Error представляет определённую ошибку провайдера, но не ошибку ADO (ошибки ADO подвергаются механизму обработки исключительных ситуаций). Используйте метод Clear, чтобы вручную очистить коллекцию Errors. Некоторые свойства и методы возвращают предупреждения, которые появляются как объекты Error в коллекции Errors, при этом не останавливая выполнение программы. Перед тем, как вы вызываете методы Resync, UpdateBatch или CancelBatch объекта Recordset, метод Open объекта Connection, или устанавливаете свойство Filter объекта Recordset, вызовите метод Clear коллекции Errors. После этого вы можете прочитать свойство Count коллекции Errors, чтобы проверить возвращенные предупреждения.

Содержит состояние объекта. Только чтение. Свойство State может принимать следующие значения:

    adStateClosed(0) — объект закрыт. adStateOpen(1) — объект открыт. adStateConnecting(2) — объект соединяется. adStateExecuting(4) — объект выполняет команду. adStateFetching(8) — объект выполняет выборку строк.

Содержит коллекцию динамических свойств соединения (объектов Property). Подробнее — см. раздел «Динамические свойства объектов».

Open(ConnectionString, UserID, Password, Options)

Открывает сеанс подключения к источнику данных. Параметры:

    ConnectionString — необязательный. Строка, определяющая параметры подключения к источнику данных. Автоматически наследует значение свойства ConnectionString объекта Connection. Вы можете или установить свойство ConnectionString объекта Connection перед вызовом метода Open, или использовать параметр ConnectionString метода Open. UserID — необязательный. Имя пользователя, используемое при соединении. Password — необязательный. Пароль пользователя. Options — необязательный. Способ подключения к источнику данных. Возможные значения:

      adAsyncConnect(16) — открывает подключение асинхронно. Чтобы определить, когда подключение станет доступным, можно обрабатывать событие ConnectComplete. adConnectUnspecified(-1) — по умолчанию. Открывает подключение синхронно.

Если вы передаете информацию о пользователе и пароле как в строке ConnectionString, так и в параметрах UserID и Password, параметры UserID и Password имеют приоритет. Закончив ваши операции с открытым подключением, используйте метод Close() для освобождения всех связанных системных ресурсов.

Закрывает соединение с источником данных. Закрытие объекта не приводит к удалению его из памяти. Можно изменить свойства объекта, а затем открыть его снова. При закрытии подключения закрываются также все активные наборы записей (объекты Recordset) для данного подключения. Объекты Command, связанные с данным подключением, уже не будут связаны с данным объектом Connection. Закрытие объекта Connection во время транзакции генерирует ошибку и ADO автоматически откатывает транзакцию.

Execute(CommandText, RecordsAffected, Options)

Выполняет запрос, оператор SQL, хранимую процедуру или любую другую команду, доступную провайдеру. Возвращает объект Recordset, доступный только для чтения курсором Forward-only, если переданная команда возвращает записи. (Если нужен объект Recordset, доступный для записи, следует создать его непосредственно, и воспользоваться его свойствами и методами.) Параметры:

    CommandText — обязательный. Строка, содержащая оператор SQL, имя таблицы, хранимой процедуры или другую команду провайдера. RecordsAffected — необязательный. Целое число (long), определяющее число записей, затронутых командой. Заполняется провайдером. Options — необязательный. Целое число (long), определяющее тип команды. Возможные значения (значения можно суммировать):

      adCmdText(1) — текстовое определение команды или хранимой процедуры. adCmdTable(2) — создать SQL-запрос, который вернёт все строки указанной таблицы. adCmdStoredProc(4) — хранимая процедура. adCmdUnknown(8) — тип команды неизвестен (по умолчанию). adAsyncExecute(16) — асинхронное выполнение команды. adExecuteNoRecords(128) — не возвращать строки.

Отменяет выполнение последнего асинхронного вызова Execute() или Open(), если действие ещё не завершено.

ConnectComplete(pError, adStatus, pConnection)

Событие возникает после того, как осуществлено подключение к источнику данных. Параметры:

    pError — содержит объект Error, если произошли ошибки (свойство adStatus равно adStatusErrorsOccurred(2)) adStatus — определяет состояние соединения. Возможные значения (для всех событий):

      adStatusOK(1) — операция произведена успешно. adStatusErrorsOccurred(2) — операция потерпела неудачу. adStatusCantDeny(3) — операция не может быть отменена. adStatusCancel(4) — произошла отмена операции. adStatusUnwantedEvent(5) — предотвращает последующие уведомления до завершения выполнения метода события.

    pConnection — объект Connection, который вызвал событие.

Событие возникает после того, как прервано подключение к источнику данных. Параметры аналогичны параметрам события ConnectComplete.

InfoMessage(pError, adStatus, pConnection)

Событие возникает каждый раз, когда генерируется предупреждение (warning). Параметры аналогичны параметрам события ConnectComplete.

WillConnect(ConnectionString, UserID, Password, Options, adStatus, pConnection)

Событие возникает перед тем, как осуществлено подключение к источнику данных. Параметры в основном аналогичны параметрам события ConnectComplete. Options — целое число (long), которое указывает способ подключения — adAsyncConnect(16) или adConnectUnspecified(-1). В обработчике события можно изменять параметры подключения.

WillExecute(Source, CursorType, LockType, Options, adStatus, pCommand, pRecordset, pConnection)

Событие возникает перед выполнением команды. Параметры:

    Source — строка, содержащая оператор SQL или имя хранимой процедуры. CursorType — тип курсора для Recordset, который будет открыт. Тип курсора можно изменять. Возможные значения:

      adOpenUnspecified(-1) — тип курсора не определён. adOpenForwardOnly(0) — определяет forward-only курсор. То же, что и статический курсор, но вы можете прокручивать записи только вперед. Это оптимизирует выполнение, если вы должны сделать только один проход по Recordset’у. adOpenKeyset(1) — Определяет keyset-курсор. То же, что и динамический курсор, но вы не можете видеть записи, добавляемые другими пользователями, хотя записи, удаляемые другими пользователями, недоступны в вашем Recordset’е. Изменения данных другими пользователями видимы. adOpenDynamic(2) — Определяет динамический курсор. Добавления, изменения и удаления другими пользователями видимы; разрешены все типы движения через Recordset, исключая закладки, если провайдер их не поддерживает. adOpenStatic(3) — Определяет статический курсор. Статическая копия набора записей, которую вы можете использовать, чтобы найти данные или генерировать отчёты. Добавления, изменения или удаления другими пользователями не видимы.

    LockType — тип блокировки для Recordset, который будет открыт. Возможные значения:

      adLockUnspecified(-1) — тип блокировки не определён. adLockReadOnly(1) — только для чтения. Вы не можете изменить данные. adLockPessimistic(2) — пессимистическая блокировка. Провайдер гарантирует успешное редактирование записей. Запись блокируется сразу после начала редактирования и до момента сохранения записей. adLockOptimistic(3) — оптимистическая блокировка. Провайдер осуществляет блокировку записей только в момент сохранения изменений, т. е. когда вы вызываете метод Update(). adLockBatchOptimistic(4) — оптимистические пакетные модификации. Требуется для пакетного режима модификации (отложенное сохранение записей).

    Options — целое число (long), указывающее опции выполнения команды или открытия Recordset’а. adStatus — определяет состояние события. Возможные значения — см. описание аналогичного параметра события ConnectComplete. pCommand — объект Command, для которого применяется это событие. pRecordset — объект Recordset, для которого применяется это событие. pConnection — объект Connection, для которого применяется это событие.

Событие WillExecute может произойти из-за вызовов Connection. Execute, Command. Execute, или Recordset. Open. Параметр pConnection всегда содержит ссылку на объект Connection. Если событие происходит из-за вызова Connection. Execute, параметры pRecordset и pCommand будут установлены в Nothing. Если событие происходит из-за вызова Recordset. Open, параметр pRecordset будет содержать ссылку на объект Recordset, а параметр pCommand будет установлен в Nothing. Если событие происходит из-за вызова Command. Execute, параметр pCommand будет содержать ссылку на объект Command, а параметр pRecordset будет установлен в Nothing.

ExecuteComplete(RecordsAffected, pError, adStatus, pCommand, pRecordset, pConnection)

Событие происходит после завершения работы команды. Параметр RecordsAffected — целое число (long) — содержит количество записей, которые затрагивает команда. Остальные параметры аналогичны одноимённым параметрам описанных выше других событий. Событие ExecuteComplete может произойти вследствие вызовов Connection. Execute, Command. Execute, Recordset. Open, Recordset. Requery или Recordset. NextRecordset.

Вызов метода BeginTrans начинает новую транзакцию. Провайдеры, которые поддерживают вложенные транзакции, при вызове метода BeginTrans в пределах открытой транзакции начинают новую, вложенную транзакцию. Возвращаемое методом BeginTrans значение указывает уровень вложения: возвращаемое значение «1» указывает, что вы открыли транзакцию верхнего уровня (то есть транзакция не вложена в пределах другой транзакции), «2» указывает, что вы открыли транзакцию второго уровня (транзакция, вложенная в пределах транзакции верхнего уровня), и т. д.

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

BeginTransComplete(TransactionLevel, pError, adStatus, pConnection)

CommitTransComplete(pError, adStatus, pConnection)

RollbackTransComplete(pError, adStatus, pConnection)

Эти события вызываются после того, как заканчивает выполняться соответствующая операция (по работе с транзакциями) на объекте Connection.

OpenSchema(QueryType, Criteria, SchemaID)

Получает информацию схемы базы данных от провайдера. Возвращает объект Recordset. Recordset будет открыт как статический курсор только для чтения. Параметры:

    QueryType — число, тип запроса схемы. Подробнее — см. MSDN, описание перечисления «SchemaEnum». Criteria — необязательный. Массив ограничений запроса (фильтр). Подробнее — см. MSDN. SchemaID — GUID для запроса схемы провайдера, не определенной спецификацией. Этот параметр требуется, если QueryType установлен в adSchemaProviderSpecific(-1); иначе этот параметр не используется.

Объект Error содержит информацию об ошибках доступа к данным, которые принадлежат отдельной операции провайдера. Вы можете обратиться к свойствам объекта Error, чтобы получить информацию о каждой ошибке:

Содержит строку, определяющую короткое описание ошибки. Это свойство по умолчанию.

Содержит уникальный код, определяющий тип ошибки (целое число).

Идентифицирует имя объекта, который вызвал ошибку (строка).

Содержит строку из пяти символов, которая указывает код ошибки по стандарту SQL ANSI.

Содержит определённый провайдером код ошибки (целое число).

Подключаемся к базе данных и выполняем запрос с помощью объекта Connection:

Set objConn = CreateObject(«ADODB. Connection»)

‘Определяем параметры подключения к базе данных

ServerName = «(local)» ‘имя или IP-адрес сервера

DSN = «master» ‘имя базы данных

U ‘логин пользователя SQL-сервера

PWD = «111» ‘пароль пользователя SQL-сервера

«Data Source=» & ServerName & _

«;Initial Catalog=» & DSN & _


objConn. ConnectionString = ConnectString

objConn. ConnectionTimeOut = 15

Set objRecordset = objConn. Execute(«SELECT name, filename FROM sysdatabases»)

‘Перебираем результаты запроса

While Not objRecordset. EOF

For i=0 To objRecordset. Fields. Count-1

strRes = strRes & CStr(objRecordset. Fields(i).Value) & vbTab

WScript. Echo Trim(strRes)

Set objConn = Nothing

Set objRecordset = Nothing

Работаем с ошибками провайдера:

Set objConn = CreateObject(«ADODB. Connection»)

‘Определяем параметры подключения к базе данных

ServerName = «(local)» ‘имя или IP-адрес сервера

DSN = «master» ‘имя базы данных

U ‘логин пользователя SQL-сервера

PWD = «111» ‘пароль пользователя SQL-сервера

«Data Source=» & ServerName & _

«;Initial Catalog=» & DSN & _

objConn. ConnectionString = ConnectString

‘Подключаемся к базе данных

‘Перебираем коллекцию ошибок

For Each E in objConn. Errors

WScript. Echo «Error. Description: » & E. Description

WScript. Echo «Error. Number: » & E. Number

WScript. Echo «Error. Source: » & E. Source

WScript. Echo «Error. SQLState: » & E. SQLState

WScript. Echo «Error. NativeError: » & E. NativeError

Set objConn = Nothing

Пример асинхронного подключения и обработки событий:

Set objConn = WScript. CreateObject(«ADODB. Connection», «Connection_»)

‘Определяем параметры подключения к базе данных

ServerName = «(local)» ‘имя или IP-адрес сервера

DSN = «master» ‘имя базы данных

U ‘логин пользователя SQL-сервера

PWD = «111» ‘пароль пользователя SQL-сервера

«;Data Source=» & ServerName & _

«;Initial Catalog=» & DSN & _

WScript. Echo «Подключаемся к базе данных (асинхронно). «

objConn. Open. 16

WScript. Echo «objConn. State = » & objConn. State

WScript. Echo «Спим две секунды. «

WScript. Sleep 2000

WScript. Echo «Закончили спать.»

WScript. Echo «Закрываем соединение. «

WScript. Echo «Снова подключаемся к базе данных (асинхронно). «

objConn. Open. 16

WScript. Echo «objConn. State = » & objConn. State

WScript. Echo «Отменяем соединение. «

Set objConn = Nothing

Set objRecordset = Nothing

Function Connection_WillConnect(ConnectionString, UserID, _

Password, Options, adStatus, pConnection)

pConnection. ConnectionString = ConnectString

WScript. Echo «WillConnect event: pConnection. State = » & pConnection. State

Function Connection_ConnectComplete(pError, adStatus, pConnection)

WScript. Echo «ConnectComplete event: pConnection. State = » & pConnection. State

Function Connection_Disconnect(adStatus, pConnection)

WScript. Echo «Disconnect event: pConnection. State = » & pConnection. State

Function Connection_InfoMessage(pError, adStatus, pConnection)

WScript. Echo «InfoMessage event: pError. Description = » & pError. Description

Пример асинхронного выполнения запроса и обработки событий:

Set objConn = WScript. CreateObject(«ADODB. Connection», «Connection_»)

‘Определяем параметры подключения к базе данных

ServerName = «(local)» ‘имя или IP-адрес сервера

DSN = «master» ‘имя базы данных

U ‘логин пользователя SQL-сервера

PWD = «111» ‘пароль пользователя SQL-сервера

«Data Source=» & ServerName & _

«;Initial Catalog=» & DSN & _

objConn. ConnectionString = ConnectString

‘Подключаемся к базе данных

Set objRecordset = objConn. Execute(«SELECT name, filename FROM sysdatabases»,,16)

‘Ждём, пока выполнится запрос

While objConn. State <> 1

WScript. Sleep 500

Set objConn = Nothing

Set objRecordset = Nothing

Function Connection_ExecuteComplete(RecordsAffected, pError, adStatus, _

pCommand, pRecordset, pConnection)

‘Перебираем результаты запроса

While Not pRecordset. EOF

For i=0 To pRecordset. Fields. Count-1

strRes = strRes & CStr(pRecordset. Fields(i).Value) & vbTab

WScript. Echo Trim(strRes)

Function Connection_WillExecute(strSource, CursorType, LockType, Options, _

adStatus, pCommand, pRecordset, pConnection)

WScript. Echo «WillExecute event: CursorType = » & CursorType

WScript. Echo «WillExecute event: LockType = » & LockType

WScript. Echo «WillExecute event: Options = » & Options

Пример работы с транзакциями:

Set objConn = WScript. CreateObject(«ADODB. Connection», «Connection_»)

‘Определяем параметры подключения к базе данных

ServerName = «(local)» ‘имя или IP-адрес сервера

DSN = «master» ‘имя базы данных

U ‘логин пользователя SQL-сервера

PWD = «111» ‘пароль пользователя SQL-сервера

«Data Source=» & ServerName & _

«;Initial Catalog=» & DSN & _


objConn. ConnectionString = ConnectString

‘Подключаемся к базе данных

Set objRecordset = objConn. Execute(«CREATE TABLE newTable (newColumn INT PRIMARY KEY)»)

Set objConn = Nothing

Set objRecordset = Nothing

Function Connection_BeginTransComplete(TransactionLevel, pError, _

WScript. Echo «BeginTransComplete event: TransactionLevel = » & TransactionLevel

Основы ADO.NET

Введение

ADO.NET – это набор классов (фреймворк) для работы с базами данных, а также XML файлами. Аббревиатура ADO расшифровывается как ActiveX Data Objects. Данная технология имеет методы и классы для извлечения и обработки данных.

Список .NET приложений, которые используют возможности ADO.NET для различных действий с БД:

ASP.NET Web Applications

Структуры подсоединения к БД

Можно определить два типа архитектуры подключения:

  1. Архитектура, подключенная к базе: подсоединена к БД на протяжении всего рабочего времени.
  2. Архитектура, не подсоединённая к БД: приложение, автоматически подключается/отключается в процессе работы. Приложения на такой архитектуре используют временные данные, хранящиеся на стороне клиента (DataSet).

ADO.NET и его библиотеки классов

На данной диаграмме видны различные типы приложений (Веб приложения, консольные приложения, приложения для Windows и так далее), использующие ADO.NET для подсоединения к БД (SQL Server, Oracle, OleDb, ODBC, XML-файлы и так далее).

Классы в ADO.NET

Также на предыдущем рисунке мы видим различные классы, а именно:

  1. Connection Class
  2. Command Class
  3. DataReader Class
  4. DataAdaptor Class
  5. DataSet.Class

1. Connection Class

Данные классы применяются в ADO.NET для подсоединения к БД.

2. Command Class

Данный класс обеспечивает хранение и выполнение SQL команд. Ниже приведены различные команды, выполняющиеся с помощью данного класса.

  • ExecuteReader: Возвращает данные к клиенту в виде строк.
  • ExecuteNonQuery: Выполняет команду, изменяющую данные в базе данных.
  • ExecuteScalar: Данный класс возвращает только одно значение.
  • ExecuteXMLReader: (Только для классов SqlClient) Получает данные из базы данных SQL Server 2000 с помощью XML-потока.

3. DataReader Class

DataReader используется для получения данных. Он используется в сочетании с Command Class для выполнения SQL-запроса.

5. DataSet Class

Класс DataSet – сердце ADO.NET, представляющее из себя набор объектов DataTable. Каждый такой объект содержит много объектов DataColumn и DataRow.

Подключение ADO.NET к базе данных

Для настройки подключения Вы должны быть знакомы со строками подключения (connection strings). ConnectionString – строка переменной (регистр не учитывается). Строки подключения нужны нам для параметра SQLConnection. Данные примеры содержат основные значения, а именно: provider, server, database, userid и password.

SQL Аутентификация

String constr= «server=.;database=institute;user > ;

String constr= «data source=.;initial catalog=institute;u > ;

Windows Аутентификация ( Windows Authentication)

String constr= «server=.;database=institute;trusted_connection=true»

String constr= «server=.;initial catalog=institute;integrated security=true»

Получение и отображение данных из базы данных

Получить и отобразить данные можно по такой схеме:

  1. Создайте объект SqlConnection, используя строку подключения.
  2. Откройте соединение.
  3. Создайте SQLCommand. Укажите тип SQLCommand.
  4. Выполните команду (используйте executereader).
  5. Получить результат (используйте SqlDataReader).
  6. Закройте соединение.
  7. Получите результат.

Ниже приведен код для подсоединения к SQL:

public partial class WebForml : System.Web.UI.Page

protected void Page_Load( object sender, EventArgs e)

SqlConnection con = new SqlConnection ( «data source=.; database=Sample; integrated security=SSPI» );

SqlCommand cmd = new SqlCommand ( «Select * from tblProduct» , con);

Компоненты ADO

В Delphi 5.0 появились компоненты для работы с Microsoft® ActiveX® Data Objects (далее ADO). ADO это технология стандартного обращения к реляционным данным от Microsoft. Эта технология аналогична BDE по назначению и довольно близка по возможностям.

Следует отличать компоненты Delphi, являющиеся частью библиотеки визуальных компонентов Delphi (VCL), и интерфейсы и объекты ADO, которые в них инкапсулированы. В дальнейшем, когда упоминается компонент — это компонент Delphi, а когда объект или интерфейс — это объект или интерфейс ADO.

Для работы с ADO на вкладке компонентов ADO есть шесть компонентов: TADOConnection, TADOCommand, TADODataSet, TADOTable, TADOQuery, TADOStoredProc .

Рис. 0. Палитра компонент ADO

  • TADOConnection аналогичен компоненту BDE TDatabase и используется для указания базы данных и работы транзакциями.
  • TADOTable — таблица доступная через ADO.
  • TADOQuery — запрос к базе данных. Это может быть как запрос, в результате которого возвращаются данные и базы (например, SELECT), так и запрос, не возвращающий данных (например, INSERT).
  • TADOStoredProc — вызов хранимой процедуры. В отличие от BDE и InterBase хранимые процедуры в ADO могут возвращать набор данных, поэтому компонент данного типа является потомком от TDataSet, и может выступать источником данных в компонентах типа TDataSource * .
  • TADOCommand и TADODataSet являются наиболее общими компонентами для работы с ADO, но и наиболее сложными в работе. Оба компонента позволяют выполнять команды на языке провайдера данных (так в ADO называется драйвер базы данных).

Разница между ними в том, что команда, исполняемая через TADODataSet , должна возвращать набор данных и этот компонент позволяет работать с ними средствами Delphi (например, привязать компонент типа TDataSource ). А компонент TADOCommand позволяет исполнять команды не возвращающие набор данных, но не имеет штатных средств Delphi для последующего использования возвращенного набора данных.

Очевидно, что все компоненты должны связываться с базой данных. Делается это двумя способами либо через компонент TADOConnection либо прямым указанием базы данных в остальных компонентах. К TADOConnection остальные компоненты привязываются с помощью свойства Connection , к базе данных напрямую через свойство ConnectionString.

База данных может быть указана двумя способами через файл линка к данным (файл в формате Microsoft Data Link, расширение UDL), либо прямым заданием параметров соединения.

Значение свойства всех ConnectionString этих компонент могут быть введены напрямую в текстовой форме, но куда проще вызвать редактор свойства нажав на кнопку » … » в конце поля ввода. Окно этого свойства выглядит так:

При выборе » Use data link file » и нажатии на кнопку » Browse… » появляется стандартный диалог выбора файла. Этот файл можно создать в любом окне explorer-а (в этом окне открытия файла, в самом explorer, на desktop и т.д.) вызвав контекстное меню и выбрав пункт » New/Microsoft Data Link «. Потом вызовите локальное меню для созданного файла и выберите в нем пункт » Open «. После этого появится property sheet описанный чуть ниже. Эти же вкладки содержит и property sheet, вызываемый через пункт » Property » локального меню UDL файла, но в нем еще есть вкладки относящиеся к самому файлу.

Использование файлов Microsoft Data Link упрощает поддержку приложений, так как возможно использовать средства Windows для настройки приложения.

При выборе в редакторе свойства » Use connection string » и нажатии на кнопку » Build… » появляется такой же property sheet, как и при выборе » Open » для Microsoft Data Link файла.

В этом окне выбирается тип базы данных, местоположение базы и параметры соединения.

На первой странице выбирается тип базы данных или Provider , в терминах ADO.

Базы MS Access доступны как через » Microsoft Jet OLE DB Provider «, так и через » Microsoft OLE DB Provider for ODBC «.

Следующая страница зависит от выбранного типа базы, однако для всех типов есть кнопка «Test connection» позволяющая проверить правильность и полноту параметров.

Для » Microsoft Jet OLE DB Provider » она выглядит так:

Checkbox «Blank password» подавляет диалог ввода идентификатора и пароля пользователя при установлении соединения, если поле пароля пустое.

Checkbox «Allow saving password » сохраняет пароль в строке параметров соединения. Если он не отмечен, то введенный пароль будет использоваться только при выполнении тестового соединения.

Для » Microsoft OLE DB Provider for ODBC » эта страница выглядит так:

Радиокнопка » Use data source name » позволяет ввести предустановленный алиас ODBC, а через «Use connection string» вводится как алиасы так и тип ODBC драйвера и параметры соединения.

Параметры идентификации пользователя аналогичны выше описанным.

На странице » Advanced » расположены дополнительные параметры, с помощью которых устанавливается уровень доступа к файлу базы данных, таймаут сетевого соединения (то есть время через которое связь будет считаться потерянной, если сервер не отвечает) и уровень глубины проверки секретности соединения.

На странице » All » можно отредактировать все параметры с предыдущих страниц и параметры зависящие от провайдера, но не вошедшие на страницу » Connection «. Редактирование осуществляется в виде параметр — значение, причем в текстовой форме, никаких диалогов нет. Помощи то же нет, эти параметры описаны только в документации на провайдер. Ее можно найти в MSDN Data Access Services/Microsoft Data Access Components (MDAC) SDK/Microsoft ActiveX Data Objects (ADO)/Microsoft ADO Programmer’s Reference/Using Providers with ADO.

В компоненте TADOConnection есть свойства Provider, DefaultDatabase и Mode которые являются альтернативным методом задания частей строки параметров соединения — провайдера, базы данных (например, пути до базы MS Access) и режима совместного использования файлов базы данных. Эти значение этих свойств автоматически включаются в строку соединения, если были заданы до активизации компонента и автоматически выставляются после соединения.

* Прим. ред. Компоненты StoredProc (и BDE и IB) могут возвращать набор данных, являются потомками TDataSet и могут выступать источником данных в компонентах типа TdataSource.

  • cоздадим простейшее приложение, состоящее из одной таблицы.
  • cоздаем форму состоящую из трех компонент
  • TADOTable с палитры компонент ADO,
  • TDataSource с палитры компонент Data Access,
  • TDBGrid cпалитры компонент Data Controls.

  • cвязываем компоненты, устанавливая
  • свойство TDBGridDataSource на компонент TDataSource,
  • свойство DataSet компонента TDataSource на компонент TADOTable.

Теперь нам необходимо указать базу данных. Делается это в свойстве ConnectionString компонента TADOTable . При нажатии на кнопку » … » появится редактор параметров соединения. Отметим радокнопку » Use data link file «, нажмите на кнопку » Browse… » и выберите в появившемся окне после файл линка к базе данных » \Program Files\Common Files\System\ole db\Data Links\DBDEMOS.UDL «. Этот линк указывает на базу в формате MS Access, входящую в поставку Delphi.

После этого в свойстве TableName компонента TADOTable выберем таблицу customer.

Активизируем компонента TADOTable , установив свойство Active в True.

Приложение можно запускать. Этот пример можно найти в директории Simple.

ADO основано на технологии COM. Все объекты и интерфейсы ADO являются интерфейсами и объектами COM.

Рис 8. Архитектура ADO

Объекты этого типа выполняют следующие функции:

  • Связь с сервером.
  • Управление транзакциями.
  • Получение информации о произошедших ошибках (свойство Errors).
  • Получение информации о схеме данных (таблицы, поля и так далее).

Рис 9. Схема взаимодействия в ADO основных COM интерфейсов

Интерфейсы Recordset и Field

Интерфейс Recordset (на нижнем уровне ADO это IRowset ) является аналогом TDataSet в Delphi.

Поддерживает текущее положение и перемещение курсора, закладки (bookmarks), чтение, изменение и удаление записей и так далее. Значение полей и их типы доступны с помощью свойства Fields.

Интерфейс Field позволяет получать значение поля, его тип длину и так далее.

Интерфейсы Command и Parameter

Эти два типа позволяют работать с командами источника данных. Синтаксис команд для каждого из источников свой.

Все объекты, кроме Parameter , имеют свойство Properties , которое позволяет получать и устанавливать параметры специфические для провайдера данных.


Библиотека довольно запутанная, многие функции дублированы в разных объектах. Например, Recordset можно создавать напрямую, методом Open , (причем предварительно создавать Connection не обязательно), можно получить как результат выполнения метода Command.Execute , либо после Connection.Execute задав команду без параметров.

Интерфейс Command инкапсулирован во все компоненты за исключением TADOConnection . Это сделано потому, что в ADO нет возможности получить данные не выполнив команду.

Интерфейс Recordset инкапсулирован в компоненты производные от TCustomADODataSet . Это компоненты TADODataSet, TADOTable, TADOQuery, TADOStoredProc .Получать данные из них возможно штатными средствами Delphi.

Возможно получение данных и при выполнении компонента TADOCommand . Метод этого компонента Execute возвращает тип _Recordset . После чего его можно, например, связать с компонентом TADODataSet следующим образом

Компоненты TADOTable, TADOQuery и TADOStoredProc являются частными случаями команды, соответственно для таблицы, SQL запроса и хранимой процедуры.

Тип Connection инкапсулируется в компонент TADOConnection .

Когда вы выполняете команду предварительно не открывая соединение, оно все равно создается. Получить к нему доступ возможно через свойство Recordset . Привязать компонент TADOConnection к уже открытому соединению возможно через свойство ConnectionObject .

Информацию о структуре базы данных можно получить с помощью метода OpenSchema компонента TADOConnection . Эта информация представлена как набор таблиц, как стандартизованных, так и специфических для провайдера. Таким способом можно узнать список таблиц, запросов, хранимых процедур и многое другое. Однако изменять структуру базы с помощью возвращаемых наборов данных невозможно.

Пример использования TADOConnection

В этом примере рассматривается работа с компонентом TADOConnection , SQL запросами с параметрами и трансакциями.

Создадим приложение из следующих компонентов

  • Connect типа TADOConnection
  • MasterSQL и DetailSQL типа TADODataSet
  • MasterDS и DetailDS типа TDataSource
  • MasterGrid и DetailGrid типа TDBGrid

Рис 10. Master-detail форма на этапе дизайна

Связываем MasterGrid, MasterDS,MasterSQL и DetailGrid,DetailDS,DetailSQL аналогично предыдущему примеру, за исключением того, что вместо типа TADOTable используется тип TADODataSet.

Привязываем Connect к базе данных. Для этого в редакторе свойства ConnectionString выбираем ту же базу данных, что и в предыдущем примере.

Для ввода SQL запросов необходимо отредактировать свойство CommandText компонентах MasterSQL и DetailSQL . После нажатия на кнопку » … » появится редактор компонент, который выглядит следующим образом

Кнопка » Add Table to SQL » добавляет в текст SQL запроса таблицу, выбранную в списке » Tables «, а » Add Field to SQL » поле таблицы, выбранное в списке » Fields «.

Запрос для MasterSQL

Запрос в DetailSQL должен выбирать только те детали, поставщик которых является текущим в MasterSQL . Для этого установим свойство DataSource компонента DetailSQL в значение MasterDS .

Запрос для DetailSQL следующий:

:VendorNo в части where — параметр запроса. Параметры при установленном DataSource берутся из него.

Активизируем MasterSQL и DetailSQL аналогично предыдущему примеру.

Приложение можно запускать. Этот пример можно найти в директории MasterDetail .

Пример использования параметров запроса

Теперь ограничим выборку поставщиков по значению поляState. Для этого добавим к форме следующие компоненты StateEdit типа TEdit c вкладки Standard , QueryButton типа TButton c вкладки Standard

Изменим запрос в MasterSQL на

:StateID — параметр, вместо которого при выполнении подставляется значение.

Добавим так же обработчик события OnClick в QueryButton следующего содержания

Программа готова. Этот пример можно найти в директории Param .

Синхронизация данных клиента и сервера.

В ADO используются три метода синхронизации данных на клиенте и сервере.

  • c помощью метода Resync, который повторно считывает записи набора. Этот метод используется при выполнении метода Refresh Delphi .
  • повторный запрос методом Requery , который заново выполняет запрос на сервере. Выполнение этого метода то же самое, что и выполнение подряд закрытия и открытия набора данных.
  • уведомление сервером клиента в случае изменения данных.

Этих методы доступны во всех компонентах имеющих набор данных. Однако эти функции доступны не для всех баз данных.

Работа с транзакциями

В компонентах ADO работа с транзакциями осуществляется через компонентTADOConnection .

Тип транзакции устанавливается в свойствеIsolationLevel одной из следующих констант:

Сервер будет использовать лучший, по его мнению, тип изоляции.

Транзакции с более высоким уровнем изоляции не могут изменять данные измененные, но не подтвержденные в текущей транзакции.

Чтение данных измененных в не подтвержденных транзакций. То есть изменения видны сразу после того как другая транзакция передала их на сервер.

То же самое что и IlReadUncommitted

Чтение данных измененных подтвержденными транзакциями. То есть изменение данных будет видимо после выполнения Commit в другой транзакции.

Изменения, сделанные другими транзакциями не видимы, но при выполнении перезапроса они транзакция может получать новый набор данных.

Транзакция не видит изменений данных произведенных другими транзакциями.

То же самое что и IlIsolated.

Обратите внимание на то, что не все типы провайдеров данных поддерживают все типы изоляции или работу с транзакциями.

Свойство Attributes устанавливает открывать ли новую транзакцию автоматически

  • xaCommitRetaining — при подтверждении транзакции
  • xaAbortRetaining — при отмене транзакции

Так же у компонента TADOConnection есть три метода для работы с транзакциями:

  • BeginTrans Начинает транзакцию
  • CommitTrans Подтверждает сделанные изменения
  • RollbackTrans Откатывает транзакцию.

Пример работы с транзакциями

За базовый возьмем пример использования TADOConnection.

Добавим к форме две кнопки (StCmButton и RollbackButton ) типа TButton , обработчики событий OnClick этих кнопок, процедуру fix_controls без параметров к форме, обработчик события OnActivate формы

Программу можно запускать. Этот пример находится в директории Trans .

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

Доступ к данным

В отличие от BDE, ADO поддерживает больше настроек работы данных.

В ADO есть понятие набора данных ( recordset ) и тесно связанное с ним понятие курсора ( cursor ). Что такое курсор в документации на ADO не описано. Однако почему то месторасположение набора данных называется положением курсора. Я думаю, что это терминологическая путаница в Microsoft и курсор то же самое что набор данных.

Во всех компонентах имеющих набор данных (то есть в TADODataSet, TADOTable, TADOQuery, TADOStoredProc ) есть свойства CursorLocation, CursorType, LockType и MarshalOptions , устанавливающие параметры обмена с сервером. Все эти свойства должны быть установлены до того, как набор данных открывается. Если вы установите их позже, то эффекта не будет.

CursorLocation — определяет, где выполняется работа с набором на клиенте ( clUseClient ) или на сервере ( clUseServer ). Если набор данных расположен на клиенте, то с сервера данные запрашиваются однократно (или до выполнения повторного запроса), в дальнейшем вся выборка данных и позиционирование идет на клиенте. Однако модификация данных производится немедленно.

CursorType — устанавливает тип курсора. Значение одно из:

  • ctUnspecified — библиотека ADO сама определяет оптимальный тип блокировки.
  • ctStatic — статический курсор. Статическая копия набора записей, которую вы можете использовать, например, для генерации отчета. Добавления, изменения или удаление записей другими пользователями не видимы.
  • сtOpenForwardOnly — идентичен статическому курсору, за исключением того, что вы можете переходить только вперед. Это тип улучшает эффективность в ситуациях, когда вы делаете только один проход через набор данных.
  • ctDynamic — динамический курсор. Добавления, изменения и удаление другими пользователями видимы и возможны все типы передвижения по набору данных. Закладки (bookmarks) возможны только, если провайдер данных их поддерживает.
  • ctKeyset — курсор набора данных. Аналогичен динамическому курсору, за исключением того, что вы не увидите записи добавленные другими пользователями, а записи удаленные другими пользователями недоступны из вашего набора данных. Изменения данных другими пользователями видимы.

Надо заметить, что TDBGrid и другие компоненты, одновременно работающие с несколькими записями, могут работать только когда закладки поддерживаются. Поэтому для компонент с которыми вы будите связывать такие компоненты должны использоваться типы ctKeyset или ctDynamic .

LockType — определяет тип блокировки записей в наборе данных. Оно из:

  • ltUnspecified — библиотека ADO сама определяет какой тип будет использоваться.
  • ltReadOnly — только чтение, изменение данных невозможно.
  • ltPessimistic — пессимистическая блокировка. Запись блокируется сразу после начала редактирования и до сохранения записей.
  • ltOptimistic — оптимистическая блокировка. Запись блокируется только когда изменения сохраняются.
  • ltBatchOptimistic — тоже самое что и ltOptimistic , но используется отложенное сохранение изменений записей. Более подробно она рассматривается в следующем пункте.
  • MarshalOptions — это свойство определяет будут ли отправлены на сервер те поля, которые не были изменены. При значении moMarshalAll будут, а при moMarshalModifiedOnly не будут.

Работа с отложенными изменениями

Обратите внимание, что в компонентах ADO нет свойства CachedUpdates , но это не означает, что невозможно отложить передачу изменений данных на сервер. Эта возможность встроена с ADO и называется Batch Updates .

Для ее использования необходимо использовать клиентский курсор (то есть установить свойство CursorLocation в clUseClient ) и LockType в ltBatchOptimistic

Так же есть метод сохраняющий изменения UpdateBatch и метод их отменяющий CancelBatch .

К каким записям из набора данных применяется действие зависит от единственного параметра этих функций

arCurrent — текущая запись

arFiltered — записи, которые попали в фильтрацию.

arAll — все записи набора.

Пример работы с отложенными изменениями .

  • За основу возьмем пример работы с транзакциями.
  • Добавим компоненты
  • BatchCB типа TCheckBox
  • ApplyButton типа TButton
  • CancelButton типа TButton
  • Добавим обработчики событий OnClick во все эти три компонента.
  • Изменим обработчик события OnActivate формы.

События ADO предназначены для той же цели, что и события VCL. Многие из них имеют аналогичные события VCL и компоненты вызывают из событий ADO события VCL. В компонентах доступны как события ADO, так и события BDE.

  • OnWillConnect — вызывается перед установкой соединения.
  • OnConnectComplete — после установки соединения.
  • OnDisconnect — при разрыве соединения.

Эти события инкапсулированы в компоненте TADOConnection.

  • OnBeginTransComplete — при выполнении BeginTrans .
  • OnCommitTransComplete — привыполнении CommitTrans .
  • OnRollbackTransComplete — привыполнении RollbackTrans .

Эти события инкапсулированы в компоненте TADOConnection.

События выполнения команд

OnWillExecute и OnExecuteComplete вызываются перед и после выполнением команды.

Эти события инкапсулированы в компоненте TADOConnection , а не в компоненте TADOCommand , как можно было бы предположить. Это связано с тем, что в ADO объекта команды как такого нет и по этой причине он не может получать сообщения.

В TADOConnection также инкапсулировано событие OnInfoMessage , которое вызывается при приходе с сервера дополнительной информации. Формат и назначение зависят от сервера, с которым вы работаете.

В ADO так же есть события связанные с набором данных, а не с соединением, как вышеописанные. Они инкапсулированы в компоненты имеющие набор данных — TADODataSet, TADOTable, TADOQuery и TADOStoredProc.

Эти события можно разбить на три группы.

1) События выборки данных

  • OnFetchProgress — многократно вызывается в процессе выборки набора данных.
  • OnFetchComplete — завершение выборки.

2) Уведомления об изменении положения текущей записи в наборе.

  • OnWillMove, OnMoveComplete — вызываются до и после изменения положения текущей записи. OnWillMove позволяет отменить действие.
  • OnEndOfRecordset — вызывается при достижении конца набора данных, позволяет добавить новую запись.

3) Уведомления об изменении набора данных

  • OnWillChangeField, OnFieldChangeComplete — до и после изменения текущей записи набора.
  • OnWillChangeRecord, OnRecordChangeComplete — вызываются до и после изменения, добавления, удаления строки набора и отмене этих действий.
  • OnWillChangeRecordset, OnRecordsetChangeComplete — вызываются до и после открытия, закрытия, повторного запроса и синхронизации набора данных.

Многие события допускают прерывание действия. Эта возможность бывает полезна при асинхронной работе с сервером. Например, для прерывания слишком длинного запроса.

Асинхронная работа с сервером

В ADO есть возможность не имеющая аналогов ни в BDE ни в InterBase. Это асинхронное выполнение операций с сервером. Могут асинхронно выполнятся установка соединения с сервером ( Connection ), выполнение команды ( Execute ) и выборка набора данных ( Fetch )

Для включения этого режима необходимо установить свойство ConnectOptions компонента TADOConnection в coAsyncConnect.

При установлении соединения происходит

Вызывается обработчик события OnWillConnect

Управление передается в программу

После окончания соединения, как успешного, так и ошибочного, вызывается обработчик события OnConnectComplete

Асинхронное выполнение команды

Надо заметить, что все компоненты ADO, за исключением компонента TADOConnection при активизации или выполнении исполняют команду ADO. Этикомпоненты TADOCommand, TADODataSet, TADOTable, TADOQuery, TADOStoredProc. Установите в свойстве ExecuteOptionseoAsyncExecute.

При исполнении происходит

Вызывается обработчик события OnWillExecute

Управление передается в программу

После окончания выполнения команды, как успешного, так и ошибочного, вызывается обработчик события OnExecuteComplete

Асинхронная выборка данных

Асинхронная выборка данных поддерживается в компонентах TADODataSet, TADOTable, TADOQuery, TADOStoredProc. Для ее включения установите в свойстве ExecuteOptionseoAsyncFetch.

После исполнения команды происходит передача данных. В процессе передачи многократно вызывается обработчик сообщения OnFetchProgress . В его параметрах есть как количество уже переданных записей, так и общее количество. Это очень удобно для создания индикаторов типа TProgressBar . После того, как выборка с сервера закончена, вызывается обработчик события OnFetchComplete.

Что не так с моим кодом ADO.NET?

Может ли кто-нибудь помочь мне идентифицировать ошибку в этой программе с помощью ADO.NET.

В коде также отображается сообщение об ошибке, связанное с отсутствующей сборкой.

В дополнение к тому, что ответил Джон, я также настоятельно рекомендую вам поместить ваши блоки SqlConnection и SqlCommand в using() — это гарантирует, что они будут удалены в конце их жизни и помогут избежать ошибок.

вы должны использовать:

Также помните: всегда открывайте соединение как можно позже (нет необходимости открывать его, когда вам еще нужно создавать другие объекты — его нужно просто открыть перед вызовом ExecuteNonQuery() ) и закрыть его явно, как только возможно (не просто оставляйте его открытым и ждать, пока произойдет finally <> ).

Илон Маск рекомендует:  Asp компонент доступа к файлам
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL