Asp обзор ado


Содержание

Asp обзор 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.NET ADO.NET code examples

В листингах кода, приведенных в данном разделе, демонстрируется извлечение данных из базы данных с помощью следующих технологий ADO.NET. The code listings in this topic demonstrate how to retrieve data from a database by using the following ADO.NET technologies:

Поставщики данных ADO.NET: ADO.NET data providers:

Платформа ADO.NET Entity Framework: ADO.NET Entity Framework:

Примеры поставщика данных ADO.NET ADO.NET data provider examples

В приведенных ниже листингах кода демонстрируется извлечение данных из базы данных с помощью поставщиков данных ADO.NET. The following code listings demonstrate how to retrieve data from a database using ADO.NET data providers. Данные возвращаются в классе DataReader . The data is returned in a DataReader . Дополнительные сведения см. в разделе Получение данных с помощью DataReader. For more information, see Retrieving Data Using a DataReader.

SqlClient SqlClient

Код в этом примере предполагает, что вы можете подключиться к Northwind образцу базы данных на Microsoft SQL Server. The code in this example assumes that you can connect to the Northwind sample database on Microsoft SQL Server. Код создает команду SqlCommand для выборки строк из таблицы Products, к которой добавляется параметр SqlParameter, ограничивающий результат строками, для которых значение UnitPrice превышает указанное значение параметра, в данном случае 5. The code creates a SqlCommand to select rows from the Products table, adding a SqlParameter to restrict the results to rows with a UnitPrice greater than the specified parameter value, in this case 5. Объект SqlConnection открывается using внутри блока, который гарантирует, что ресурсы закрываются и удаляются при выходе из кода. The SqlConnection is opened inside a using block, which ensures that resources are closed and disposed when the code exits. Команда выполняется с помощью объекта SqlDataReader, а результаты выводятся в окно консоли. The code executes the command by using a SqlDataReader, and displays the results in the console window.

OleDb OleDb

Данный образец кода предполагает возможность подключения к образцу базы данных Northwind из Microsoft Access. The code in this example assumes that you can connect to the Microsoft Access Northwind sample database. Код создает команду OleDbCommand для выборки строк из таблицы Products, к которой добавляется параметр OleDbParameter, ограничивающий результат строками, для которых значение UnitPrice превышает указанное значение параметра, в данном случае 5. The code creates a OleDbCommand to select rows from the Products table, adding a OleDbParameter to restrict the results to rows with a UnitPrice greater than the specified parameter value, in this case 5. Соединение OleDbConnection открывается в блоке using , что гарантирует закрытие и освобождение ресурсов после завершения работы кода. The OleDbConnection is opened inside of a using block, which ensures that resources are closed and disposed when the code exits. Команда выполняется с помощью объекта OleDbDataReader, а результаты выводятся в окно консоли. The code executes the command by using a OleDbDataReader, and displays the results in the console window.

Odbc Odbc

Данный образец кода предполагает возможность подключения к образцу базы данных Northwind из Microsoft Access. The code in this example assumes that you can connect to the Microsoft Access Northwind sample database. Код создает команду OdbcCommand для выборки строк из таблицы Products, к которой добавляется параметр OdbcParameter, ограничивающий результат строками, для которых значение UnitPrice превышает указанное значение параметра, в данном случае 5. The code creates a OdbcCommand to select rows from the Products table, adding a OdbcParameter to restrict the results to rows with a UnitPrice greater than the specified parameter value, in this case 5. Объект OdbcConnection открывается using внутри блока, который гарантирует, что ресурсы закрываются и удаляются при выходе из кода. The OdbcConnection is opened inside a using block, which ensures that resources are closed and disposed when the code exits. Команда выполняется с помощью объекта OdbcDataReader, а результаты выводятся в окно консоли. The code executes the command by using a OdbcDataReader, and displays the results in the console window.

OracleClient OracleClient

Данный пример кода предполагает наличие соединения с базой данных DEMO.CUSTOMER на сервере Oracle. The code in this example assumes a connection to DEMO.CUSTOMER on an Oracle server. Кроме того, необходимо добавить ссылку на файл System.Data.OracleClient.dll. You must also add a reference to the System.Data.OracleClient.dll. Этот код возвращает данные в объекте OracleDataReader. The code returns the data in an OracleDataReader.

Примеры Entity Framework Entity Framework examples

В приведенных ниже листингах кода демонстрируется извлечение данных из источника данных путем выполнения запросов к сущностям модели EDM. The following code listings demonstrate how to retrieve data from a data source by querying entities in an Entity Data Model (EDM). В этих примерах используется модель, основанная на образце базы данных Northwind. These examples use a model based on the Northwind sample database. Дополнительные сведения о Entity Framework см. в разделе Общие сведения о Entity Framework. For more information about Entity Framework, see Entity Framework Overview.

LINQ to Entities LINQ to Entities

В данном примере кода запрос LINQ используется для возврата данных в виде объектов Categories, которые проецируются в анонимный тип, содержащий только свойства CategoryID и CategoryName. The code in this example uses a LINQ query to return data as Categories objects, which are projected as an anonymous type that contains only the CategoryID and CategoryName properties. Дополнительные сведения см. в разделе LINQ to Entities обзор. For more information, see LINQ to Entities Overview.

Типизированный запрос ObjectQuery Typed ObjectQuery

В данном примере кода для возврата данных в виде объектов Categories используется запрос ObjectQuery . The code in this example uses an ObjectQuery to return data as Categories objects. Дополнительные сведения см. в разделе запросы объектов. For more information, see Object Queries.

EntityClient EntityClient

В данном примере кода для выполнения запроса Entity SQL используется команда EntityCommand. The code in this example uses an EntityCommand to execute an Entity SQL query. Этот запрос возвращает список записей, представляющих экземпляры типа сущности Categories. This query returns a list of records that represent instances of the Categories entity type. Для доступа к записям данных в результирующем наборе используется объект EntityDataReader. An EntityDataReader is used to access data records in the result set. Дополнительные сведения см. в разделе Поставщик EntityClient для Entity Framework. For more information, see EntityClient Provider for the Entity Framework.

LINQ to SQL LINQ to SQL

В данном примере кода запрос LINQ используется для возврата данных в виде объектов Categories, которые проецируются в анонимный тип, содержащий только свойства CategoryID и CategoryName. The code in this example uses a LINQ query to return data as Categories objects, which are projected as an anonymous type that contains only the CategoryID and CategoryName properties. Этот пример основан на контексте данных Northwind. This example is based on the Northwind data context. Дополнительные сведения см. в разделе Начало работы. For more information, see Getting Started.

Компоненты 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.

Веб-формы ASP.NET

Обзор технологии ADO.NET

Для заполнения элемента dgChair данными из таблицы базы данных мы будем использовать ADO.NET, поэтому нужно добавить в файл showGrid.aspx пространство имен для классов данных, необходимых для доступа к источнику данных. Веб-формы по умолчанию содержат пространство имен System.Data , являющееся главным пространством имен ADO.NET. Другие пространства имен, подчиненные System.Data , поддерживают определенные типы источников данных. Стандартными пространствами имен, подчиненными System.Data , являются следующие.

Пространство имен SqlClient обеспечивает интерфейс к провайдеру SQL Server и наиболее эффективный способ связи с SQL Server 2000. Пространство имен System.Data.OleDb поддерживает интерфейс, аналогичный традиционной технологии ADO; оно неэффективно при подключении к SQL Server 2000. System.Data.Ole.Db рекомендуется для работы с источниками данных, отличными от SQL Server 2000, имеющими провайдера OLE-DB. Пространства имен System.Data.Common и System.Data.SqlTypes обеспечивают интерфейсы для SQL Server и общие интерфейсы между SQL Server и классами OLE-DB.

ADO.NET поставляется в виде единственной библиотеки – System.Data.dll . Если необходима поддержка источника данных ODBC, Microsoft предлагает другую библиотеку (ее можно загрузить из интернета) для обеспечения пространства имен классов ODBC.

Поскольку источником данных, рассматриваемым в примерах данной лекции, является Microsoft Acess 2000, то следует использовать пространство имен OleDb . Если источником данных является SQL Server 2000, то используется пространство имен SqlClient – это наиболее эффективный способ установки связи с SQL Server 2000. Вверху файла showGid.aspx необходимо вместе с остальными директивами пространства имен ввести следующую строку кода:

Использование классов ADO.NET для заполнения элемента управления DataGr >После установки соединения выполняется запрос экземпляра набора данных ADO.NET myDataSet таблицы tblChairs базы данных. Набору данных DataSet при инициализации присваивается имя myChairs . Инициализируется объект ADO.NET Adaptor для заполнения экземпляра myDataSet . После этого инициализируется объект ADO.NET DataView с именем myDataView с использованием первой таблицы набора данных myDataSet . В итоге аргумент DataGrid с именем dg , переданный подпрограмме, устанавливает свойство источника данных на экземпляр DataView с именем myDataView , и вызывает метод DataBind аргумента dg для заполнения экземпляра dg элемента DataGrid данными из таблицы tblChairs .

Использование класса DataView не является обязательным, если нужно отобразить весь набор данных DataSet . В элементе dg (см. листинге 2.10) отображается весь созданный набор данных DataSet , поэтому можно опустить следующую строку:

Свойство DataSource элемента dg установим равным значению Tables[0] свойства набора данных myDataSet . Строку, присваивающую dg.DataSource источнику myDataView , изменим следующим образом:

При нажатии на клавишу F5 будет скомпилирована страница showGrid.aspx , затем откроется окно браузера с отображением данных в таблице myChairs (см. рис. 2.6).

Применение элемента управления DataList

Помимо DataGrid для отображения информации из базы данных используются и другие типы элементов управления данными. Элемент управления DataList применяется для отображения данных в формате, отличном от табличной формы. В листинге 2.11 приведен исходный код файла datalist .aspx.cs , представляющий собой веб-форму, в которой элемент управления DataList заполняется данными с помощью набора ADO.NET Dataset .

DataList использует иной механизм построения DataSet , называемый шаблоном. Шаблон описывает способ отображения данных в элементе управления DalaList . Щелкните правой кнопкой мыши на DataList и выберите любую из опций редактирования шаблона в команде Edit Template (Изменить шаблон) контекстного меню. В шаблоне настраиваются заголовки или имена полей, определяющие отображение данных. В DataList присутствуют также верхние, нижние колонтитулы и названия. Для указания данных из определенного набора DataSet необходимо изменить шаблон в представлении HTML. Теги и %> означают присоединение данных в странице веб-формы. В коде шаблона указываются поля присоединения данных. В листинге 2.12 приведен код файла datalist .aspx , отображаемый в представлении HTML.

DataList определяется элементами HTML DataList > . Внутри тегов элемента DataList располагаются теги шаблона, определяемые тегом . Свойства шаблона в дизайнере веб-форм генерируют теги внутри тегов , однако их можно отредактировать вручную в представлении HTML. Теги присоединения данных можно стратегически расположить внутри шаблона в тех местах, где должны отображаться соответствующие поля набора данных DataSet . В листинге 2.12 приведены два поля из отображаемого набора DataSet – ID и Color . Тег присоединения для поля ID имеет вид , а тег присоединения поля Color – .

При запуске datalist .aspx сгенерирован тот же набор DataSet , как в примере с элементом DataGrid (см. рис. 2.6). Однако формат данных отличается от предыдущего примера (см. рис. 2.7), поскольку данные отформатированы по шаблону, приведенному в листинге 2.12.

ГЛАВА 4

Модель ADO.NET: провайдеры данных

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

В этой главе преследуется цель изложить основные принципы функционирования технологии ADO.NET. Здесь обсуждаются базовые операции и описываются базовые объекты провайдера данных ADO.NET, в частности Connection, Command, Parameter и DataReader. Далее (в главах 5, «ADO.NET: объект DataSet», 6, «ADO.NET: объект DataAdapter», и 7, «ADO.NET: дополнительные компоненты») рассматриваются более сложные объекты, которые тесно связаны с основным объектом ADO.NET — DataSet.

Обзор технологии ADO.NET

Разработчики приложений для работы с базами данных на основе Visual Basic уже привыкли к тому, что Microsoft каждые несколько лет предлагает новую усовершенствованную модель доступа к данным. Кроме новой трехбуквенной аббревиатуры, технология ADO.NET также предлагает новую модель API-интерфейсов и объектов. В течение последних нескольких лет разработчики уже успели познакомиться с предшественниками ADO.NET — технологиями ODBC, DAO, RDO и ADO. При знакомстве с каждой новой технологией им требовалось тщательно изучить ее назначение и принципы работы. При этом они часто задавали себе один и тот же вопрос: имеет ли смысл переходить на новую технологию? В большинстве случаев ответ был положительным, если только новшества не оказывали никакого влияния на текущие и будущие требования проекта. Действительно, чаще всего переход на новые технологии был вполне обоснован, за исключением технологии RDO (Remote Data Objects) для проектов с процессором баз данных Jet (потому что технология ОАО по-прежнему является более удачной технологией работы с Jet).

Мотивация и философия

Итак, зачем же все-таки нужна новая объектная модель доступа к данным? Наиболее простой ответ на этот вопрос можно сформулировать по аналогии с рекламным лозунгом компании Toyota конца 1970-х годов: «Спрашивали? Так получите». Технология ADO.NET предоставляет множество функциональных возможностей, о которых разработчики мечтали с момента появления технологии ADO. Некоторые компоненты, например отсоединенные от источника данных наборы записей и поддержка XML, были добавлены в модель ADO уже после ее выпуска. Но, поскольку они являлись добавлениями к основной модели, которые отсутствовали в исходной архитектуре ADO, способ их применения был крайне неудобным.

Классическая модель ADO основана на модели COM и одном объекте recordset, применение которого может быть весьма разнообразным. В зависимости от параметров конфигурации, например типа курсора, его расположения и типа блокировки, объект recordset будет действовать по-разному и выполнять различные операции.

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

Это дает разработчику возможность специализированного применения объектов без дополнительного обременительного «багажа». В то же время совершенно разные объекты могут взаимодействовать друг с другом для выполнения более сложных функций.

Поддержка распределенных приложений и отсоединенной модели программирования

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

Расширенная поддержка XML

Хотя классическая модель ADO способна сохранять и считывать данные в формате XML, фактически используемый для этого формат имеет несколько необычную форму и не так прост в применении. Кроме того, поддержка XML в модели ADO была добавлена в ходе ее эволюции, а потому обладает некоторыми ограничениями, в то время как поддержка XML в технологии ADO.NET является ее ключевым элементом. Философия ADO.NET формулируется очень кратко и просто: «Данные — это данные». Независимо от источника поступления, они могут считываться и обрабатываться как реляционные или иерархические данные, исходя из поставленной задачи и используемых инструментов.

XML используется как формат передачи данных между уровнями и компьютерами. Это не только исключает проблему прохождения COM-объектов через брандмауэры, но и позволяет совместно использовать данные сразу несколькими приложениями, которые работают на платформах, отличных от Windows (так как практически любая платформа способна обрабатывать текстовые данные XML).

Интеграция с .NET Framework

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

Внешний вид объектов ADO.NET

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

ADO.NET И ADO 2.X

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

• В классической модели ADO предусмотрен присоединенный к источнику данных способ доступа и использование физической модели данных.

• В модели ADO.NET проводиться четкое разделение между присоединенным способом доступа к данным и отсоединенной моделью программирования.

• В модели ADO.NET нет свойств CursorType, CursorLocation или LockType, потому что в ADO.NET предусмотрены только статические курсоры, клиентские курсоры и оптимистическая блокировка.

• Вместо использования простого многоцелевого объекта recordset в ADO.NET разные функции распределены среди объектов меньшего размера — DataReader, DataSet и DataTable.

• В ADO.NET разрешается полноценное манипулирование данными в формате XML, а не только использование его в качестве формата ввода-вывода данных.

В ADO.NET предусмотрена поддержка строго типизированных наборов данных DataSet, а не использование для всех полей типа Variant. Это позволяет эффективнее обнаруживать ошибки времени выполнения и повышает производительность работы приложений.

Место ADO.NET в архитектуре .NET Framework

На рис. 4.1 показано место классов ADO.NET в архитектуре.NET Framework. В основе этой платформы лежит общеязыковая исполняющая среда (Common Language Runtime — CLR), которая образует единую среду выполнения для всех .NET-совместимых приложений, независимо от используемого языка программирования. Среда CLR включает общую систему типов, управление памятью и жизненным циклом объектов.

На следующем логическом уровне над средой CLR располагаются базовые системные классы. Именно эти классы отвечают за выполнение базовых функций, которые могут использоваться в .NET-приложениях. На рис. 4.1 показаны только некоторые классы библиотеки классов .NET Framework, которая, по сути, является новым набором API-интерфейсов Windows. В прошлом доступ к функциям операционной системы Windows осуществлялся только через API-интерфейсы, которые состояли из большого набора разрозненных и плохо продуманных функций. На платформе.NET Framework такой доступ организован на основе свойств и методов, которые предлагаются базовыми системными классами. Это объектно-ориентированный, последовательный и комфортабельный способ создания приложений Windows, независимо от типа клиентского приложения: традиционного настольного приложения, броузера или Web-службы.

РИС. 4.1. Классы ADO.NET в структуре платформы .NET Framework

Этот уровень включает несколько пространств имен (групп классов и других определений), предназначенных для организации доступа к данным: System.Data, System.OleDb и System.Data.SqlClient. В оставшейся части данной главы, а также в главах 5, 6 и 7 эти классы и пространства имен рассматриваются более подробно.

Прикладные интерфейсы

На этом наиболее высоком уровне происходит дифференциация, или разделение, выполняемых функций, которые разработчики могут использовать в разных типах приложений. Он содержит классы и элементы управления для создания (классических) приложений Windows на основе форм (Windows Forms), другие классы и элементы управления для создания Web-ориентированных приложений (Web Forms), а также классы для создания приложений на основе Web-служб. Однако все они используют для прикладной логики базовую библиотеку классов — системные базовые классы.

Теперь после первого знакомства с расположением классов ADO.NET в общей структуре платформы.NET Framework рассмотрим подробнее основные объекты ADO.NET.

Провайдеры данных ADO.NET

Несмотря на подчеркнутое значение отсоединенной модели программирования, для извлечения, обновления, вставки и удаления данных все же придется подключиться к физической базе данных. Программное обеспечение ADO.NET для подсоединения и взаимодействия с физической базой данных называется провайдером данных ADO.NET. Провайдер данных (data provider) — это управляемый код .NET, который эквивалентен провайдеру OLEDB или драйверу ODBC. Провайдер данных состоит из нескольких объектов, которые реализуют необходимую функциональность в соответствии с определениями своих классов и интерфейсов.

В настоящее время существует три разных провайдера данных ADO.NET, каждый из которых определен в своем собственном пространстве имен. Для всех объектов в этих пространствах имен используются следующие префиксы: OleDb, Sql и Odbc. Однако при упоминании этих объектов в рамках своего пространства имен имя объекта можно указывать без употребления префикса данного пространства имен.

Провайдер данных SqICIient

Оптимизирован для работы с SQL Server версии 7.0 (или выше) и позволяет добиться более высокой производительности по следующим причинам:

• взаимодействует с базой данных непосредственно через собственный протокол табличной передачи данных (Tabular Data Stream — TDS), а не через OLEDB с отображением интерфейса OLEDB на протокол TDS;

• исключает накладные расходы, связанные с использованием COM-служб взаимодействия;

• отсутствуют ненужные функции, которые не поддерживаются в SQL Server (объекты этого провайдера данных находятся в пространстве имен System.Data.SqlClient).

Провайдер данных Oledb

Основан на существующем COM-поставщике OLEDB и COM-службах взаимодействия платформы .NET Framework, предназначенных для доступа к базе данных. Этот провайдер данных используется для работы с SQL Server более ранних версий, чем 7.0. Он позволяет осуществлять доступ к любой базе данных, для которой имеется поставщик OLEDB. Объекты этого провайдера данных находятся в пространстве имен System.Data.Oledb.

Провайдер данных Odbc

Используется для доступа к базам данных, которые не имеют собственного провайдера данных .NET или COM-поставщика OLEDB. Иногда драйвер ODBC демонстрирует более высокую производительность, чем драйвер OLEDB, поэтому для сравнения их фактической производительности при работе с конкретной базой данных рекомендуется провести ряд тестов. Объекты этого провайдера данных находятся в пространстве имен System. Data.Odbc.

Создание провайдера данных для ODBC несколько задержалось и отстало от создания платформы .NET Framework и Visual Studio .NET. Поэтому он не был включен в исходный выпуск Visual Studio .NET и его можно скопировать с Web-узла компании Microsoft. Кроме того, в скором будущем следует учитывать возможное появление дополнительных .NET-совместимых провайдеров данных.

В настоящее время на Web-узле компании Microsoft также можно скопировать провайдер данных Oracle.NEТ. Эти провайдеры данных ОDBС и Oracle будут включены в следующую версию 1.1 платформы .NET Framework и Visual Studio .NET 2003. В результате этого пространство имен провайдера данных ODBC Microsoft.Data.Odbc станет называться System.Data.Odbc.

В примерах этой главы используется провайдер данных ODBC версии 1.0, поэтому при использовании провайдера данных ODBC версии 1.1 нужно изменить имя его пространства имен.

Основные объекты

Каждый провайдер данных имеет четыре основных объекта, которые указаны в табл. 4.1.

Таблица 4.1. Основные объекты провайдера данных

Объект Краткое описание
Connection Устанавливает соединение с указанным источником данных
Command Выполняет команду по отношению к источнику данных. Содержит коллекцию объектов Parameters и методы для выполнения команд разного типа
DataReader Считывает данные и возвращает из источника поток данных, предназначенный только для чтения и только в одном направлении
DataAdapter Соединяет набор данных DataSet и источник данных для извлечения и сохранения данных

Каждый объект основан на базовом родовом классе и реализует родовой интерфейс, но имеет собственную реализацию. Например, объекты SqlDataAdapter, OleDBDataAdapter и OdbcDataAdapter являются производными от класса DbDataAdapter и реализуют те же интерфейсы. Однако каждый из них реализует их своим собственным способом для соответствующего источника данных.

Пространство имен System. Data. OleDb содержит объекты:

Пространство имен System.Data.SqlClient содержит объекты:

Пространство имен Microsoft.Data.Odbc содержит объекты:

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

Объект Connection

Этот объект модели ADO.NET очень похож на объект Connection в классической модели ADO. Его предназначение очевидно: он служит для установления соединения с заданным источником данных и с указанным в строке подключения учетным именем и паролем. Соединение можно настроить, редактируя нужным образом значения параметров строки подключения. Объект Command (или DataAdapter) может затем использовать это подключение для выполнения нужных операций с источником данных.

В отличие от объекта Connection в модели ADO в объекте Connection в модели ADO.NET нет методов Execute и ОpenSchema. Для выполнения команд SQL следует использовать объекты Command или DataAdapter. Функции метода OpenSchema реализуются с помощью методов GetOleSchemaTable объекта OleDbConnection.

Хотя объекты OleDbConnection, SqlConnection и OdbcConnection реализуют одинаковые интерфейсы, они все же имеют разные реализации. Например, они имеют разный формат строки подключения. В объекте OleDbConnection используется стандартный формат строки подключения OLEDB с незначительными исключениями. В объекте OdbcConnection также используется стандартный формат строки подключения ODBC, но с незначительными отклонениями. Наконец, в объекте SqlConnection используется совершенно другой формат строки подключения, который имеет отношение только к SQL Server версии 7.0 или выше.

Более того, некоторые объекты обладают дополнительными свойствами. Например, объект OleDbConnection имеет свойство Provider для указания используемого провайдера данных OLEDB, а объект OdbcConnection имеет свойство Driver для указания используемого драйвера ODBC. Объект SqlConnection вообще не имеет этих свойств, так как используется с предопределенным источником данных, т.е. с SQL Server. Однако он имеет свойства PacketSize и WorkstationID, которые используются только для работы с SQL Server и не нужны для других типов подключения.

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

1. Запустите интегрированную среду разработки приложений Visual Studio .NET.

2. Создайте новый проект Visual Basic Windows Application. Для этого в диалоговом окне New Project (Новый проект) выберите тип проекта Visual Basic Project в области Project Types (Типы проектов), а затем шаблон Windows Application (Приложение Windows) в области Templates (Шаблоны).

3. Назовите проект DataProviderObjects.

4. Укажите путь к файлам проекта.

5. Увеличьте размер формы Form1.

6. В окне Properties укажите значение Data Provider Objects для свойства Text формы Form1.

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

8. В окне Properties укажите значение cmdConnection для свойства (Name) и значение Connection для свойства Text этой кнопки.

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

10. В окне Properties укажите значение txtResults для свойства (Name), значение True для свойства Multiline и значение Both для свойства ScrollBars этого текстового поля.

11. Увеличьте размер текстового поля, чтобы оно занимало до 80% всей площади формы.

По окончании этих операций форма будет выглядеть так, как на рис. 4.2.

РИС. 4.2. Форма Form1 проекта DataProviderObjects

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

Обратите внимание, что эти пространства имен содержат классы и определения объектов ADO.NET для каждого провайдера данных.

Среда Visual Studio .NET может не обнаружить пространство имен Data.Odbc, потому что оно является расширением базовой версии продукта. В таком случае выполните ряд действий.

1. Скопируйте инсталлятор провайдера данных ODBC с Web-узла компании Microsoft и выполните все инструкции по инсталляции.

2. В окне SolutionExplorer щелкните правой кнопкой мыши на папке References проекта DataProviderObjects.

3. Выберите в контекстном меню команду Add Reference.

4. Во вкладке.NET диалогового окна Add Reference прокрутите список компонентов и найдите файл Microsoft.Data.Odbc.dll.

5. Щелкните дважды на файле Microsoft.Data.Odbc.dll для включения его в список избранных компонентов Selected Components в нижней части диалогового окна Add Reference.

6. Щёлкните на кнопке ОК для закрытия диалогового окна Add Reference.

Если по какой-либо причине не распознано какое-то другое импортированное пространство имен, потребуется привести ссылку на файл System.Data.dll. Для этого выполните действия, перечисленные в пп. 2-6, где вместо файла Microsoft.Data.Odbc.dll при выполнении п. 4 нужно использовать файл System.Data.dll.

Теперь для кнопки btnConnection нужно создать код, приведенный в листинге 4.1, для создания подключения к базе данных pubs сервера SQL Server. Этот код создает подключение и отображает состояние подключения до и после попытки подключения к базе данных.

Листинг 4.1. Код открытия подключения и отображения его состояния

Private Sub btnConnection Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnConnection.Click

‘ Создание экземпляра объекта Connection

Dim cnn As SqlConnection = New SqlConnection()

‘ Отображение состояния подключения

If (cnn.State = System.Data.ConnectionState.Open) Then

txtResults.Text = txtResults.Text & «Connection is Open»

txtResults.Text = txtResults.Text & «Connection is Closed»

txtResults.Text = txtResults.Text & ControlChars.CrLf

txtResults.Text & «Opening DB connection…» _

‘ Отображение состояния подключения

If (cnn.State = System.Data.ConnectionState.Open) Then

txtResults.Text = txtResults.Text & «Connection is Open»

txtResults.Text = txtResults.Text & «Connection is Closed»

txtResults.Text = txtResults.Text & ControlChars.CrLf

Новым полезным компонентом Visual Basic .NET является возможность получения текстового представления для значений перечисления (enum) вместо создания специальной подпрограммы на основе операторов select-case для всех возможных значений перечисления. Все типы перечисления, которые являются объектами, наследуют метод ToString, возвращающий строку с текстовым представлением текущего значения. В листинге 4.1 используется приведенный ниже фрагмент кода для отображения состояния подключения на основе операторов if-else.

‘ Отображение состояния подключения – вариант 1

If (cnn.State = System.Data.ConnectionState.Open) Then

txtResults.Text = txtResults.Text& «Connection is Open»

txtResults.Text = txtResults.Text& «Connection is Closed

Его можно заменить другим вариантом кода, содержащим только одну строку.

‘ Отображение состояния подключения вариант 2

txtResults.Text & «Connection is » & cnn.State.ToString & ControlChars.CrLf

После запуска полученного приложения DataProviderObjects и щелчка на кнопке Connection в текстовом поле появятся строки о закрытии подключения, о состоянии подключения и повторном открытии подключения, как показано на рис. 4.3.

При создании рабочего кода нужно выбрать и реализовать стратегию обработки исключительных ситуаций для большинства подпрограмм и операций. Обычно основана на блоках try-catch обработки исключительных ситуаций. Этот код не включен в приведенные здесь примеры, потому что наша цель — сфокусировать внимание на концепциях программирования баз данных, а не на описании общих принципов программирования для Visual Basic .NET.

Объект Command

Аналогично объекту Connection, объект Command модели ADO.NET очень похож на своего предшественника из прежней модели ADO 2.X. Объект Command позволяет выполнять команды по отношению к источнику данных и получать возвращенные данные или результаты выполнения команд.

РИС. 4.3. Состояние приложения DataProviderObjects до и после открытия подключения с помощью кода из листинга 4.1

Этот объект имеет следующие свойства: CommandText и СommandType для определения текста и типа фактической команды; Connection для указания подключения, используемого для выполнения команды; СommandTimeout для указания времени ожидания, по истечении которого команда отменяется и выдается сообщение об ошибке; Parameters для коллекции параметров команды; Transaction для указания транзакции, в которой используется данная команда.

Все три версии объекта Command (в пространствах имен OleDb, Sql, Odbc) имеют идентичные свойства и методы, за исключением того, что объект SqlCommand имеет дополнительный метод, которого нет у двух других вариантов этого объекта, а именно ExecuteXmlReader. Он использует преимущества SQL Server для автоматического возвращения данных в формате XML (если в запрос SQL добавлено предложение FOR XML).


Еще одно отличие между версиями объекта Command для разных провайдеров данных заключается в использовании значений свойства CommandType. Все они поддерживают значения Text и StoredProcedure, а объекты OleDbCommand и SqlCommand поддерживают еще одно, третье возможное значение — TableDirect. Это позволяет эффективно загружать все содержимое таблицы за счет установки значения TableDirect для свойства CommandType и имени таблицы для свойства CommandText.

Продолжим работу с формой, показанной на рис. 4.3.

1. Добавим еще одну кнопку сразу под кнопкой btnConnection, перетаскивая пиктограмму кнопки из панели элементов управления.

2. В окне свойств Properties установите значение btnCommand для свойства Name и значение Command для свойства Text.

3. Добавьте для кнопки код, показанный в листинге 4.2.

Листинг 4.2. Код открытия подключения к базе данных и подготовки объекта Command

Private Sub btnCommand_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnCommand.Click

‘ Создание экземпляра объекта Connection

Dim cnn As SqlConnection = New SqlConnection( _

‘ Создание экземпляра объекта Command

Dim cmd As SqlCommand = New SqlCommand() txtResults.Clear()

‘ Указание подключения и текста команды

«Select au_lname, state from authors»

txtResults.Text = «Command String:» & ControlChars.CrLf

txtResults.Text = txtResults.Text & ControlChars.Tab & cmd.CommandText() & ControlChars.CrLf

После запуска на выполнение приложения DataProviderObjects щелкните на кнопке Command, и в текстовом поле будет показана команда SQL, которая находится в свойстве CommandText объекта SqlCommand, а именно: SELECT au_lname, state FROM authors.

Многие классы платформы .NET Framework, а также созданные другими разработчиками классы перегружают конструкторы объектов. Иначе говоря, существует несколько способов создания нового экземпляра класса, где каждый конструктор принимает свойственный только ему набор аргументов. Таким образом можно выбрать версию, оптимальную для выполнения текущей задачи. Конструктор в листинге 4.2 для объекта SqlConnection отличается от го по умолчанию конструктора в листинге 4.1, в котором не используется никаких аргументов. Позже строке подключения присваивается объект SqlConnection с помощью свойства ConnectionString.

‘ Создание экземпляра объекта Connection

Dim cnn As SqlConnection = New SqlConnection()

В листинге 4.2 используется конструктор объекта SqlConnection, который принимает строку подключения в качестве параметра. Это позволяет создать объект и сразу же указать для него строку подключения в одной строке кода.

‘ Создание экземпляра объекта Connection

Dim cnn SqlConnection = New SqlConnection(«server=localhost;u >

Применение объекта Command с параметрами и хранимыми процедурами

При создании запросов или команд для источника данных часто требуется передавать значения параметров действия (обновление, вставка или удаление данных) или хранимой процедуры. Для решения этой проблемы в объекте Command предусмотрено свойство Parameters, которое является объектом-коллекцией ParameterCollection и содержит коллекцию объектов-параметров Parameter. Это аналогично способу работы, применимому в модели ADO 2.X.

Объекты Parameter и ParameterCollection тесно связаны с соответствующим провайдером данных, поэтому они должны быть реализованы как составная часть провайдера данных ADO.NET. Способы программирования объекта SqlParameterCollection и использование объектов OdbcParameterCollection и OledbParameterCollection имеют существенные отличия. Объекты OdbcParameterCollection и OledbParameterCollection основаны на позиционных параметрах, а объект SqlParameterCollection – на именованных параметрах. Эти различия в значительной степени влияют на способ определения запросов и параметров.

Начнем с создания простого запроса с параметрами для извлечения из базы данных pubs имен и фамилий всех авторов из заданного штата.

С одной стороны, при использовании провайдеров данных OLEDB или ODBC запрос будет иметь следующий вид:

SELECT state, au_fname, au_lname from authors WHERE state = ?

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

С другой стороны, при использовании провайдера данных SqlClient запрос будет выглядеть следующим образом:

SELECT state, au_fname, au_lname from authors WHERE state = @MyParam

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

Объект Parameter можно создать явно, используя конструктор Parameter (т.е. с использованием оператора New) или передавая нужные аргументы методу Add объекта-коллекции ParameterCollection (свойство Parameters объекта Command). Помните, что оба метода (конструктор Parameter и метод Add) имеют перегруженные версии.

Ниже приведен один из способов включения параметра команды за счет явного указания объекта-параметра.

Dim rayParameter As New OdbcParameter(«@MyParam», OdbcType.Char, 2)

А способ включения параметра команды с помощью метода Add выглядит иначе.

Второй метод короче и обычно предпочтительнее, если только нет особой причины для повторного использования объекта Parameter.

Для метода Add объекта Parameter обычно требуется указать имя, тип и длину параметра. Затем нужно указать направление передачи данных: Input, Output, InputOutput или ReturnValue. По умолчанию используется направление Input. Наконец, для присвоения значения параметру нужно использовать свойство Value объекта Parameter. Кроме того, для параметра можно указать другие свойства, например масштаб (свойство Scale), точность (свойство Precision) и допустимость использования неопределенных значений (свойство IsNullable).

При использовании провайдера данных SqlClient можно применять практически идентичный код. Единственным отличием являются префиксы Odbc вместо префиксов Sql, а также тип перечисления SqlDbType вместо OdbcType.

Dim myParameter As New SqlParameter(«@MyParam», SqlDbType.Char, 2)

Аналогично выглядит способ включения параметра команды с помощью метода Add.

Для передачи параметру неопределенного значения можно использовать свойство Value объекта DBNull.

Измените код кнопки cmdButton, как показано в листинге 4.3. После запуска программы и щелчка на кнопке cmdButton в текстовом поле появится текст запроса, а также имя и значение параметра.

Листинг 4.3. Код подготовки и отображения команды и ее параметров

Private Sub btnCommand_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnCommand.Click

‘ Создание экземпляра объекта Connection

Dim cnn As SqlConnection = New SqlConnection( _

‘ Создание экземпляра объекта Command и объектов Parameter

Dim cmd As SqlCommand = New SqlCommand()

Dim prm As SqlParameter = New SqlParameter()

‘ Указание подключения и текста команды

«Select au_lname, state from authors where state = @MyParam»

‘ Создание параметра и указание его значения

cmd.Parameters.Add(New SqlParameter(«@MyParam», SqlDbType.Char, 2))

txtResults.Text = «Command String:» & ControlChars.CrLf

txtResults.Text = txtResults.Text & ControlChars.Tab & _

txtResults.Text = txtResults.Text & «Command parameters:» & _

For Each prm In cmd. Parameters

txtResults.Text = txtResults.Text & ControlChars.Tab & _

prm.ParameterName & » = » & prm.Value & ControlChars.CrLf

Аналогично вызываются хранимые процедуры, за исключением того, что вместо свойства CommandType.Text используется свойство CommandType.StoredProcedure, а имя хранимой процедуры присваивается свойству CommandText. Таким образом, код вызова хранимой процедуры GetAuthorsFromState с двухсимвольным параметром для извлечения информации обо всех авторах заданного штата будет выглядеть, как показано ниже.

Для вызова хранимой процедуры с помощью OdbcCommand нужно использовать стандартные последовательности символов ODBC (с участием фигурных скобок), а не только имя процедуры для свойства CommandText. В качестве заменителей параметров в ODBC используются вопросительные знаки. Вот как выглядит приведенный выше для провайдера данных ODBC:

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

Чтобы хранимая процедура возвращала значение, нужно указать направление Output, а затем считать значение свойства параметра после вызова хранимой процедуры. В данном примере также определяется возвращаемое значение хранимой процедуры. Поскольку здесь указан тип Int сервера SQL Server, то для этого параметра не нужно указывать длину, так как по определению она составляет 4 байт.

cmd.Parameters.Add(New SqlParameter(«result», SqlDbType.Int)

cmd. Parameters («result»).Direction = ParameterDirection.ReturnValue

cmd.Parameters.Add(New SqlParameter(«@MyParam», SqlDbType.Int)

При определении параметра, который будет использоваться для возвращаемого значения ReturnValue хранимой процедуры его нужно указать первым в списке параметров коллекции Parameters. Это обязательное условие для провайдеров данных OLEDB и ODBC, потому что, как отмечалось выше, параметры этих провайдеров определяются по порядку их расположения, а возвращаемое значение может располагаться только с начала. Однако при определении возвращаемого значения для провайдера данных SQL его можно pасполагать в произвольном месте коллекции параметров, потому что параметры провайдера данных SQL определяются по именам.

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

Выполнение команд

До сих пор мы только указывали свойства и параметры объекта Command, но не выполняли эти команды. Существует три стандартных способа выполнения команд для объекта Command и один способ для объекта SqlCommand.

• Метод ExecuteNonQuery. Выполняет команду SQL и не возвращает записей.

• Метод ExecuteScalar. Выполняет команду SQL и возвращает первое поле первой записи.

• Метод ExecuteReader. Выполняет команду SQL и возвращает набор записей с помощью объекта DataReader.

• Метод ExecuteXmlReader (только для объекта-команды SqlCommand). Выполняет команду SQL и возвращает набор записей в формате XML с помощью объекта XmlReader.

Первые три метода рассматриваются далее в этой главе, а последний – в главе 10, «ADO.NET и XML», при обсуждении способов использования XML в модели ADO.NET.

Метод ExecuteNonQuery

Этот метод позволяет выполнять команды без возвращения значений (наборов записей или скалярных значений), кроме значения, сообщающего об успешном или неудачном исходе выполнения команды. Это наиболее эффективный способ выполнения команд по отношению к источнику данных. Таким образом можно выполнять команды SQL или хранимые процедуры, которые являются DDL-командами определения данных (например, для создания или изменения структуры базы данных: таблиц, представлений или хранимых процедур) либо DML-командами управления данными (например, их обновления, вставки или удаления).

Метод ExecuteNonQuery возвращает только целочисленное значение, сообщающее об успешном или неудачном исходе выполнения команды.

При удачном выполнении DDL-команд определения данных для изменения структуры баз данных возвращается значение -1, а при удачном выполнении DML управления данными для их обновления, вставки или удаления возвращается количество строк, задействованных в команде. При неудачном выполнении команд обоих типов возвращается значение 0.

Продолжая работу с проектом DataProviderObjects, попробуем использовать объекты пространства имен OleDb и базу данных pubs. Наша задача – создать новую таблицу tblStateZipCodes для этой базы данных с помощью DDL-команды. Новая таблица tblStateZipCodes предназначена для организации связи между почтовыми индексами и штатами. Определения ее полей совпадают с определениями полей в других таблицах базы данных pubs, но отличаются от определений полей в других таблицах базы данных Novelty. Эта таблица имеет два поля: ZipCode для почтового индекса и State для названия соответствующего штата. Ниже приведена команда SQL для создания этой таблицы.

Теперь нужно изменить исходную форму Form1, выполнив ряд действий.

1. Откройте форму Form1 в интегрированной среде разработки Visual Studio .NET.

2. В верхнем левом углу формы создайте еще одну кнопку, перетаскивая ее пиктограмму из панели элементов управления.

3. В окне свойств Properties укажите значение btnNonQuery для свойства (Name) и значение ExecuteNonQuery для свойства Text.

Затем создайте код подпрограммы btnNonQuery_Click, который приведен в листинге 4.4.

Листинг 4.4. Код создания таблицы базы данных с помощью объектов пространства имен OleDb

Private Sub btnNonQuery_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnNonQuery.Click

‘ Создание экземпляра объекта Connection.

Dim cnn As OleDbConnection = New OleDbConnection( _

Dim sql As String Dim result As Integer

‘ Создание экземпляра объекта Command.

Dim cmd As OleDbCommand = New OleDbCommand()

‘ Указание подключения и текста команды

‘ Указание команды SQL для создания новой таблицы

sql = «CREATE TABLE tblStateZipCodes (» & _

‘ Открытие подключения перед вызовом метода ExecuteNonQuery.

‘ Для обработки исключительных ситуаций нужно поместить

‘ код в блоке Try-Catch, потому что неудачное выполнение

‘ команды ТАКЖЕ генерирует ошибку времени выполнения.

‘ Отображение сообщения об ошибке.

‘ Вывод результатов выполнения команды.

MessageBox.Show(«Command completed successfully»)

‘ MessageBox.Show(«Команда выполнена успешно»)

MessageBox.Show(«Command execution failed»)

После запуска полученного приложения и щелчка на кнопке ExecuteNonQuery сначала появится диалоговое окно с сообщением об успешном выполнении команды. Правильность выполнения команды можно проверить, просматривая список таблиц базы данных pubs в диалоговом окне Server Explorer интегрированной среды разработки Visual Studio .NET (которое описывается в главе 1, «Основы построения баз данных») или в программе SQL Server Enterprise Manager (которая рассматривается в главе 3, «Знакомство с SQL Server 2000»).

При повторном щелчке на кнопке ExecuteNonQuery появятся два диалоговых окна с сообщениями: одно с сообщением о возникшей исключительной ситуации (оно создается блоком обработки исключительных ситуаций try-catch), а другое — о неудачном выполнении команды.

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

sql = «CREATE VIEW EmployeeJobs_view AS» & _

«SELECT TOP 100 PERCENT jobs. job_desc,» & _

Для включения предложения ORDER BY в определение представления с сортировкой результатов нужно включить в команду SELECT предложение ТОР.

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

Листинг 4.5. Код, содержащий команду SQL для создания хранимой процедуры AuthorsInState1

sql = «CREATE PROCEDURE AuthorsInState1 @State char(2)» & _

» select @result = count (*) from authors » & _

Хотя метод не возвращает записи, входные и выходные параметры, а также возвращаемые значения можно передавать или возвращать с помощью коллекции Parameters. Это более эффективный подход, чем выполнение команды, которая возвращает набор записей или скалярное значение.

Обратимся теперь ко второму типу команд SQL для управления данными, т.е. их обновления, вставки или удаления. Для этих команд обычно требуется указать параметры, особенно при работе с хранимыми процедурами.

Продолжая работу с проектом DataProviderObjects, предположим, что издательство, которое создало базу данных pubs, решило повысить авторам выраженный в процентах гонорар. Включение новой кнопки и нового текстового поля в форму позволяет главному бухгалтеру издательства повысить гонорары авторов с помощью параметра команды UPDATE. Для этого нужно выполнить перечисленные ниже действия.

1. Создайте новую кнопку под кнопкой cmdExecuteNonQuery.

2. В окне свойств Properties для этой кнопки укажите значение cmdUpdate для свойства (Name) и значение Update для свойства Text.

3. Создайте новое текстовое поле под новой кнопкой Update.

4. В окне свойств Properties для этого текстового поля укажите значение txtParam1 для свойства (Name) и значение 0 для свойства Text. Установка такого значения гарантирует, что при запуске программы и случайном нажатии кнопки Update не будет причинен ущерб данным.

5. Создайте код подпрограммы btnUpdate_Click, приведенный в листинге 4.6.

Листинг 4.6. Код обновления таблицы базы данных с помощью команды UPDATE с параметром

Private Sub btnUpdate_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnUpdate.Click

‘ Создание экземпляра объекта Connection.

Dim cnn As SqlConnection = New SqlConnection(_

‘ Создание экземпляра объекта Command.

Dim cmd As SqlCommand = New SqlCommand()

‘ Указание подключения и текста команды.

cmd.CommandText = «UPDATE roysched SET royalty = royalty + @param1»

‘ Создание параметра и указание его значения.

cmd.Parameters.Add(New SqlParameter(«@param1», SqlDbType.Int))

‘ Открытие подключения перед вызовом метода ExecuteReader().

MessageBox.Show(result & » records updated», «DataProviderObjects»)

Теперь таблицу с гонорарами авторов в базе данных pubs можно обновить, запустив приложение DataProviderObjects, задав новое значение гонорара в текстовом поле под кнопкой Update и щелкнув на этой кнопке. После этого на экране появится диалоговое окно с указанием количества охваченных записей. Этот результат можно проверить с помощью программы SQL Server Enterprise Manager, просматривая данные о гонорарах в таблице roysched до и после обновления.

Точно такое же обновление можно выполнить с помощью хранимой процедуры, что позволяет добиться более высокой производительности и централизованно хранить код. Потенциальным недостатком использования хранимых процедур является необходимость назначения администратора базы данных или специалиста с опытом создания хранимых процедур. В крупных организациях порой уходят целые дни на то, чтобы администратор базы данных изменил хранимые процедуры, которые можно самостоятельно изменить за несколько минут. Хранимые процедуры создаются с помощью программ SQL Server Enterprise Manager или SQL Query Analyzer, которые описаны в главе 3, «Знакомство с SQL Server 2000». Это можно также сделать с помощью проекта DataProviderObjects, изменив команду SQL, как это делалось ранее.

Итак, в данном примере хранимая процедура имеет следующий вид:

CREATE PROCEDURE UpdateRoyalties

UPDATE roysched SET royalty = royalty + @param1

В листинге 4.6 для организации вызова хранимой процедуры потребуется заменить свойства CommandText и CommandType объекта Command.

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

Метод ExecuteScalar

Иногда нужно выполнить команду, которая возвращает скалярное значение, т.е. только одно значение. Типичными примерами являются команды SQL для вычисления суммы всех значений SUM и общего количества значений COUNT. Другими примерами являются справочные таблицы для подстановки одного значения или команды, возвращающие логическое значение. Метод ExecuteScalar выполняет заданную команду и возвращает значение первой записи из первого поля возвращенного набора записей, а все другие поля и записи игнорируются.

Включим приведенную ниже хранимую процедуру в базу данных pubs.

CREATE PROCEDURE AuthorsInState2

SELECT count(*) FROM authors WHERE state = @param1

Хранимая процедура AuthorsInState2 принимает параметр, который имеет двухсимвольный код штата, и возвращает из таблицы authors количество авторов из этого штата. Эта процедура с функциональной точки зрения эквивалентна процедуре AuthorsInState1 из листинга 4.5, но возвращает вычисленное значение для набора записей, а не только индикатор успешности выполнения команды.

Использование метода ExecuteScalar вместо метода ЕxecuteNonQuerу и передача скалярного значения с помощью параметра ReturnValue связаны с дополнительными накладными расходами. Зачем же его используют? Он проще в употреблении, потому что не нужно заботиться об указании параметров в определениях и вызовах команд.

Для вызова данной хранимой процедуры с помощью провайдера данных ODBC выполните следующее.

1. Создайте дополнительную кнопку под текстовым полем txtParam1.

2. В окне свойств Properties укажите значение cmdScalar для свойства (Name) и значение ExecuteScalar для свойства Text.

3. Создайте код подпрограммы btnExecuteScalar_Click, приведенный в листинге 4.7.

Листинг 4.7. Код извлечения скалярного значения из хранимой процедуры с помощью провайдера данных ODBC

Private Sub btnExecuteScalar_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnExecuteScalar.Click

‘ Создание экземпляра объекта Connection.

Dim cnn As OdbcConnection = New OdbcConnection( _

‘ Создание экземпляра объекта Command.

Dim cmd As OdbcCommand = New OdbcCommand()

‘ Указание подключения и текста команды.

‘ Создание параметра и указание его значения

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

MessageBox.Show(«Count is » & result, «DataProviderObjects»)

Запустите приложение и введите в текстовом поле над кнопкой ExecuteScalar двухсимвольный код штата. После щелчка на кнопке ExecuteScalar появится диалоговое окно с сообщением о количестве авторов в данном штате. Полученный результат можно проверить с помощью программы SQL Server Enterprise Manager, просматривая данные в таблице authors в базе данных pubs.

Учтите, что по умолчанию база данных pubs содержит двух авторов из штата Юта (код UТ) и 15 авторов из штата Калифорния (код СА).

Метод ExecuteReader

Этот метод применяется для возвращения набора записей. В большинстве приложений для работы с базами данных именно он используется чаще всего. Работа этого метода основана на объекте DataReader, с помощью которого записи обрабатываются последовательно одна за другой. Более подробно метод ExecuteReader и объект DataReader рассматриваются в следующем разделе.

Объект DataReader

Данный объект предназначен для чтения в прямом направлении небуферизуемого потока записей, полученных от метода ExecuteReader объекта Command. Объект DataReader в основном эквивалентен объекту Recordset модели ADO 2.X, который также предназначен для чтения в прямом направлении. Объект DataReader предлагает наиболее быстрый способ доступа к источнику данных, но в нем не предусмотрены возможности прокрутки и обновления данных. Поскольку данные не буферизуются и не сохраняются в кэше, этот метод прекрасно подходит для извлечения большого объема данных. Для перехода к следующей записи объекта DataReader нужно вызвать его метод Read.

Кроме коллекции Fields, доступ к полям каждой записи можно осуществить с помощью строго типизированных методов. Доступ к полям с помощью коллекции Fields аналогичен способу доступа к полям в модели ADO 2.X.

Объект DataReader не имеет явного конструктора, т.е. его нельзя создать с помощью оператора New(). Для инициализации нового объекта нужно вызвать метод ExecuteReader объекта Command.

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

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

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

1. Создайте под кнопкой ExecuteScalar дополнительную кнопку.

2. В окне свойств Properties укажите значение cmdExecuteReader для свойства (Name) и значение ExecuteReader для свойства Text.

3. Создайте код подпрограммы btnExecuteReader_Click, приведенный в листинге 4.8.

Кроме способов использования объекта DataReader, в этом примере демонстрируются и другие функциональные возможности. Например, здесь помимо членов Text и StoredProcedure свойства-перечисления CommandType для указания типа команды используется член TableDirect. Он содержит имя таблицы, все поля которой возвращаются данной командой. Учтите, что этот член перечисления поддерживается только для провайдера данных ODBC.

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

Private Sub btnExecuteReader_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnExecuteReader.Click

‘ Создание экземпляра объекта Connection.

Dim cnn As OleDbConnection = New OleDbConnection( _

‘ Создание экземпляра объекта Command.

Dim As OleDbCommand = New OleDbCommand()

‘ Указание подключения и текста команды

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

Dim reader As OleDbDataReader

txtResults.Text = txtResults.Text & reader(«fname») & _

ControlChars.Tab & ControlChars.Tab & _

(Здесь предполагается, что представление EmployeeJobs_view уже создано с помощью подпрограммы btnNonQuery_Click из листинга 4.4, как описано выше. – Прим. ред.)

Перед попыткой доступа к данным объекта DataReader не забывайте вызывать метод Read(). В отличие от объекта Recordset в модели ADO 2.X, в которой после загрузки данных текущее расположение автоматически находится на первой записи, в модели ADO.NET в объекте DataReader нужно явно указать текущее расположение возле первой записи с помощью исходного вызова метода

Для организации доступа к данным можно также применить цикл While с более эффективными строго типизированными методами доступа к полям.

txtResults.Text = txtResults.Text & reader.GetString(1) & _

ControlChars.Tab & reader.GetString(2) & _

ControlChars.Tab & ControlChars.Tab & _

reader. GetString(0) & ControlChars.Ctrlf

Еще одно изменение, которое диктуется личным вкусом и стилем программирования автора, заключается в объединении определения объекта DataReader и выполнения метода ExecuteReader в одной строке, т.е. вместо фрагмента кода

Dim reader As OleDbDataReader reader = cmd.ExecuteReader()

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

Dim reader As OleDbDataReader = cmd.ExecuteReader()

После запуска приложения DataProviderObjects щелкните на кнопке ExecuteReader, и в текстовом поле справа будут отображены данные из представления EmployeeJobs_view, как показано на рис. 4.4.

РИС. 4.4. Результаты выполнения команды ExecuteReader из листинга 4.8

По окончании использования объекта DataReader следует вызвать метод Close. Дело в том, что выходные данные или возвращаемые значения объекта Command недоступны до тех пор, пока объект DataReader открыт. Он остается открытым до тех пор, пока открыто само подключение или объект DataReader.

Объект DataReader также предлагает простой и эффективный способ создания Web-страниц для работы сданными на основе элемента управления DataGrid, который подробно рассматривается в главе 11, «Web-формы: приложения на основе ASP.NET для работы с базами данных».

Использование объектов Connection и Command во время создания приложения

Вкладка Data панели элементов управления среды Visual Studio .NET содержит компоненты, которые соответствуют некоторым методам доступа к данным. С помощью окна Properties они позволяют указывать значения свойств во время создания приложения, а не только во время его выполнения. Они также предлагают визуальные инструменты указания значений для более сложных свойств.

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

1. Создайте еще одну форму Form2 в проекте DataProviderObjects.

2. В окне свойств Properties укажите значение Connection and Command Components для свойства Text формы Form2.

3. Увеличьте размер формы.

4. Включите в форму текстовое поле Textbox1.

5. В окне свойств Properties укажите значение True для свойства Multiline и значение Both для свойства Scrollbars этого текстового поля.

6. Увеличьте размер текстового поля так, чтобы оно покрывало большую часть формы.

7. Из вкладки Data панели элементов управления перетащите элемент управления OleDbConnection в форму Form2. Этот компонент невидим во время выполнения приложения, поэтому он появится в разделе невизуальных компонентов в нижней части окна редактирования формы.

8. В окне свойств Properties укажите приведенное ниже значение для свойства ConnectionString элемента управления OledbConnection1.

9. Из вкладки Data панели элементов управления перетащите еще один элемент управления OleDbCommand в форму Form2. Этот компонент также невидим во время выполнения приложения, поэтому он появится в нижней части окна редактирования формы.

10. В окне свойств Properties укажите значение OledbConnection1 для свойства Connection и приведенное ниже значение для свойства CommandText элемента управления OledbCommand1.

SELECT * FROM EmployeeJobs_view

11. Создайте код подпрограммы Form2_Load, приведенный в листинге 4.9.

В главе 6, «ADO.NET: объект DataAdapter» представлены графические инструменты, которые позволяют автоматически создать строку подключения и текст команды SQL вместо создания вручную их кода.


Private Sub Form2_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

‘ Открытие подключения перед вызовом метода ExecuteReader.

Dim reader = OleDbCommand1.ExecuteReader()

TextBox1.Text = TextBox1.Text & reader(«fname») & _

ControlChars.Tab & ControlChars.Tab & _

‘ Отмена выбора всех строк в текстовом поле.

12. Щелкните правой кнопкой мыши на проекте DataProviderObjects в окне Solution Explorer и выберите команду Properties в контекстном меню.

13. В папке Common Properties выберите элемент General, а затем выберите форму Form2 в текстовом поле Startup object (Объект запуска) данного приложения.

После запуска приложения DataProviderObjects в текстовом поле формы Form2 будут отображены данные из представления EmployeeJobs_view, как показано на рис. 4.5.

Другие провайдеры данных

Выше были представлены классы нескольких основных провайдеров данных (например, Parameter и Parameters), а также четыре основных объекта в табл. 4.1. В главе 5, «ADO.NET: объект DataSet», более подробно рассматривается объект DataSet и связанные с ним объекты, а в главе 6, «ADO.NET: объект DataAdapter», – объект DataAdapter.

В оставшейся части главы рассматривается еще один провайдер данных — объект-транзакция Transaction. Транзакции используются для гарантированного успешного завершения сразу нескольких связанных операций по принципу «все или ничего». Это значит, что либо все операции транзакции успешно выполняются, либо они вообще не выполняются. Классическим примером транзакции является банковская операция перечисления денежных средств. Эта операция состоит из двух этапов: удержание денежной суммы с одного счета и зачисление ее на другой счет. При этом желательно избегать ситуаций, когда успешно выполняется только первый этап транзакции!

РИС. 4.5. Результаты отображения данных в форме Form2 с помощью элементов управления OleDbConnection и OleDbCommand

Провайдеры данных ADO.NET содержат объект Transaction, который имеет фундаментальные методы обработки транзакций. Метод Commit фиксирует текущую транзакцию, а метод Rollback – откатывает (отменяет) текущую транзакцию. Выполнение транзакции и создание объекта Transaction осуществляется с помощью вызова метода BeginTransaction по отношению к открытому объекту Connection. Способ использования объекта Transaction демонстрируется на примере бизнес-ситуации 4.1.

Бизнес-ситуация 4.1: создание процедуры для архивирования старых заказов по годам

После относительно длительного использования системы управления базами данных некоторые данные рекомендуется архивировать. В каждой рабочей системе операцию архивирования следует включить в состав обязательных и регулярно выполняемых операций резервного копирования. Архивируемые данные — это данные, которые нужны не для постоянного использования (т.е. в оперативном режиме), а только изредка. Удаление этих данных из основных оперативных таблиц базы данных может повысить производительность операций доступа к этим таблицам, так как при этом приходится обрабатывать и фильтровать меньше записей. Однако архивная таблица часто хранится в идентичном формате таблицы и доступ к ней в случае необходимости можно организовать аналогичным образом. В этой бизнес-ситуации создается простая форма для выполнения простого архивирования данных из таблицы tblOrder базы данных Novelty. Она позволит выбирать и архивировать заказы по годам, т.е. после выбора нужного года выполняются перечисленные ниже действия.

1. Сначала в базе данных создается новая таблица tblOrderXXXX, где ХХХХ обозначает тот год, записи о заказах которого будут архивироваться.

2. Затем все записи о заказах за указанный год копируются из таблицы tblOrder втаблицу tblOrderXXXX.

3. Все скопированные записи о заказах за указанный год удаляются из таблицы tblOrder.

Хитрость здесь заключается в том, чтобы отменить всю транзакцию при неудачном выполнении какой-либо ее операции. Нам не нужна новая таблица, если в нее нельзя скопировать данные. Не нужно архивировать данные, если они не удаляются из основной таблицы. Аналогично, не нужно удалять никакие записи из основной таблицы, если они не скопированы в архивную таблицу. Для решения этой задачи можно использовать объект Transaction и вернуть (откатить) базу данных в исходное состояние в случае сбоя каких-то операций. Для создания формы с этими функциями выполните перечисленные ниже действия.

Запустите интегрированную среду разработки Visual Studio .NET.

2. Создайте новый проект Visual Basic Windows Application.

3. Назовите проект BusinessCase4.

4. Укажите путь к файлам проекта.

5. Увеличьте размер формы Form1.

6. В окне Properties укажите значение frmArchive для свойства (Name) и значение Archive Orders для свойства Text формы Form1.

7. Создайте в форме поле со списком lstYears, надпись Label1, кнопку bntOK и кнопку btnCancel, перетаскивая их из панели элементов управления.

8. В окне Properties укажите значение Archive all orders for the year для свойства Text надписи, значение OK для кнопки btnOK и значение Cancel для кнопки btnCancel.

9. Расположите все элементы управления, как показано на рис. 4.6.

РИС. 4.6. Расположение элементов управления в форме frmArchive

В верхней части файла с исходным кодом вставьте приведенную ниже строку кода для импорта пространства имен SqlClient.

В теле определения класса для формы frmArchive включите код из листинга 4.10.

Листинг 4.10. Код архивирования данных в новой таблице

Private Sub frmArchive_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

Private Sub btnCancel_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnCancel.Click

Private Sub btnOK_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnOK.Click

‘ Создание экземпляров объектов Connection и Command.

Dim cnn As SqlConnection = New SqlConnection( _

‘ Размещение кода внутри блока Try-Catch для

‘ обработки исключительных ситуаций.

‘ Открытие объекта Connection и запуск транзакции.

‘ Указание команды SQL для вставки соответствующих

sql = «SELECT * INTO tblOrder» & SelectedYear & _

FROM tblOrder WHERE year (OrderDate) = » & SelectedYear

‘ Передача текста команды SQL в транзакцию.

‘ Отображение результатов вставки записей в архивную таблицу.

records = result MessageBox.Show(records & _

» records inserted successfully into tblOrder» & SelectedYear)

«No records inserted into tblOrder» & SelectedYear)

‘ При отсутствии записей созданная таблица

‘ не нужна и транзакцию нужно откатить.

‘ Команда SQL для удаления соответствующих

sql = «delete FROM tblOrder WHERE year (OrderDate) = » _

‘ Эта команда находится в той же транзакции.

‘ Показать результаты удаления записей.

‘ Все действия успешно выполнены, можно фиксировать транзакцию.

‘ Какие-то действия не выполнены, поэтому нужно

‘ Отображение сообщения об ошибке.

ControlChars.CrLf & ControlChars.CrLf & _

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

Подпрограмма btnCancel_Click обработки щелчков мышью на кнопке Cancel просто закрывает форму, что в данном случае приводит к закрытию программы. Все необходимые действия выполняются обработчиком щелчков мышью на кнопке OK. После объявлений переменных следует получить выбранный год из списка lstYears и сохранить его для дальнейшего использования. Для гарантированной отмены транзакции в случае возникновения любой исключительной ситуации следует окружить активный код блоком Try-Catch-Finally.

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

Первые два этапа создания архивной таблицы и копирования выбранных строк выполняются с помощью одной команды SELECT, которая содержит предложение INTO имя_таблицы. Указанная таким образом таблица создается автоматически, а если такая таблица уже существует, то генерируется исключительная ситуация. Выбранное значение года добавляется к имени таблицы tblOrder для создания имени новой архивной таблицы.

Команда SELECT INTO не создает индекс, если он существует в исходной таблице. Для повышения производительности выполнения запросов по отношению к данной таблице, вероятно, придется создать индексы по одному или нескольким полям.

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

Если хотя бы одна запись скопирована в таблицу, то ее прототип в исходной таблице tblOrder удаляется с помощью команды DELETE, содержащей предложение WHERE с заданным годом. В случае успешного выполнения этой команды, т.e. если количество скопированных и удаленных строк совпадает, транзакция считается успешно завершенной и фиксируется. В противном случае, т.е. если какая-то отдельная операция завершится неудачно (нарушится процесс удаления записей, будет отменено разрешение на удаление архивируемых данных или произойдет сбой сервера), вся транзакция будет отвергнута. Откат транзакции гарантирует, что при неудачной попытке удаления корректных записей из таблицы tblOrder архивная таблица tblOrderХХХХ будет удалена.

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

Еще один блок Try-Catch потребуется для обработки исключительной ситуации, когда архивная таблица не может быть создана (например, из-за наличия именно такой таблицы). Основная причина, по которой она предлагается, заключается в том, что транзакция началась, но никаких изменений данных не произошло, а потому в файл регистрации транзакций не записано никаких действий, которые нужно откатить.

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

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

Резюме

В этой главе приводятся общие сведения об ADO.NET и некоторых объектах провайдеров данных .NET. Провайдеры данных образуют интерфейс ADO.NET для взаимодействия с физическими хранилищами данных и предлагают модель программирования в режиме подключения. Здесь кратко рассматриваются свойства и методы объектов Connection, Command, Parameter, DataReader и Transaction, включая стандартные провайдеры данных SqlClient, OleDb и Odbc. В главе 5, «ADO.NET: объект DataSet», описываются способы работы с данными в отключенном режиме на основе объектов DataSet и DataAdapter.

Вопросы и ответы

Судя по содержанию этой главы, модель ADO.NET предназначена для работы в отключенном режиме и нет никакой поддержки для серверных курсоров или пессимистической блокировки. А что же делать, если уже существующее приложение использует их или спецификации нового проекта требуют их применения? Следует ли мне использовать для этого только Visual Basic 6.0?

Во-первых, необходимо тщательно проанализировать приложение и убедиться в том, что действительно всегда нужно использовать серверные курсоры или пессимистические блокировки. Если они (или какие-то другие компоненты, которые не поддерживаются в ADO.NET) действительно необходимы, не стоит отчаиваться. Visual Basic. NET все равно можно использовать для таких приложений, так как на платформе .NET Framework предусмотрена расширенная поддержка взаимодействия с COM, что позволяет использовать в .NET-совместимом приложении COM-объекты, которые, в свою очередь, могут использовать управляемый (.NET-совместимый) код. Иначе говоря, можно использовать не только ADO 2.X, но и любые другие COM-объекты, для которых нет аналогов в .NET. Конечно, за организацию взаимодействия между COM и.NET придется заплатить снижением производительности. В какой мере? Ответ на этот вопрос можно получить только после тщательного тестирования приложения.

Похоже, что программирование объектов, методов и свойств ничем не отличается от способов их программирования в модели ADO 2.X. Зачем же переходить к модели ADO.NET?

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

1. Visual Basic .NET и платформа.NET представляют собой совершенно новый мир, а модель ADO.NET является способом доступа к данным в этом мире.

2. Хотя при создании .NET-совместимых приложений можно продолжать использование уже существующих COM-компонентов, например из модели ADO 2.X, такой способ связан с сокращением производительности при доступе к COM-компонентам и необходимости их корректной инсталляции и регистрации.

Обзор ASP.NET профайлеров

Почти год назад была опубликована статья об использовании профилировщика приложений в Visual Studio 2010. В комментариях была высказана мысль о том, что неплохо было бы сравнить сей продукт с аналогичными. Попробую провести краткий обзор и сравнение 4-х самых известных профайлеров .NET.

В обзоре участвуют:

  • встроенный в Visual Studio 2010 (начиная с Premium редакции) профайлер (MSDN, блог);
  • ANTS Perfomance profiler от RedGate;
  • dotTrace от JetBrains;
  • EQATEC Profiler от EQATEC.

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

Так как по роду деятельности я связан с разработкой под web, то в качестве подопытного будет выступать ASP.NET приложение (скачать):

  1. public partial class Default : System.Web.UI. Page
  2. <
  3. protected void Page_Load( object sender, EventArgs e)
  4. <
  5. SampleBadMethod1();
  6. SampleBadMethod2();
  7. >
  8. private void SampleBadMethod1()
  9. <
  10. for ( int i = 0; i private void SampleBadSubMethod1()
  11. <
  12. Thread.Sleep(10);
  13. >
  14. private void SampleBadMethod2()
  15. <
  16. for ( int i = 0; i private void SampleBadSubMethod2()
  17. <
  18. Thread.Sleep(1);
  19. >
  20. >

* This source code was highlighted with Source Code Highlighter .

Небольшое лирическое отступление. Сначала хотел выбрать реальное приложение для профайлинга. Выбор пал на Tailspin Spyworks, которое используется в качестве steb-by-step руководства. Казалось бы, руководство для новичков должно быть так отполировано, чтобы сразу заинтересовать разработчика, научить каким-то правильным вещам. И что я там увидел? Кривоватую вёрстку, смесь бизнес-логики и разметки, неоптимальные запросы к БД, select * даже если тянутся 1-2 поля… Выполнять все оптимизации 4 раза (для 4-х профайлеров) оказалось очень трудоёмко, поэтому за 3 минуты было написано используемое в тестах приложение. Если кому-то интересно, в будущих статьях можно будет разобрать по косточкам Tailspin Spyworks.

Довольно лирики, запускаем профайлеры.

Visual Studio Perfomance Profiler

Запуск производится из VS через меню Analyze -> Launch Perfomance Wizard.
С помощью нескольких простых шагов выбираем тип профайлинга (я выбрал Instrumentation, т.к. в CPU sampling не показывается время выполнения, только в процентах), исследуемые проекты и нужно ли профилировать запросы к БД через ADO.NET.
После нажатия кнопки Finish запускается браузер, при этом в студии будет висеть заставка с кнопками Pause и Stop.

После окончания загрузки страницы в браузере, нажимаем Stop и получаем результат:

Не будем останавливаться на описании профайлера, это достаточно хорошо сделано тут, тут и тут.

Вот как выглядит экран статистики по методам:

Теперь нужно оптимизировать критичные участки кода SampleBadMethod1 и SampleBadMethod2. В качестве «оптимизации» сокращаем количество итераций в цикле (например, со 100 до 50 и c 10000 до 1000).
Получаем ещё раз результат и через пункт меню Analyze->Compare Perfomance Reports сравниваем результат:

Ну что же, мы молодцы, получилось ускорить наше приложение.

Повторим те же действия с другими профайлерами.

ANTS Profiler

При создании новой сессии профайлинга появляется следующее окно:

Здесь можно выбрать тип приложения, опции профайлинга и ввести данные приложения, например, для ASP.NET application на dev-сервере это путь до приложения, версия .net, номер порта и т.п.
После нажатия кнопки Start Profiling запускается браузер, в ANTS Profiler в это время рисуется график загрузки процессора по оси времени.
Нажимаем кнопку Stop Profiling и получаем результат:

Подробно рассматривать назначение и функции областей экрана сейчас не буду (это тема отдельной статьи), кратко скажу, что в верхней части видно временную шкалу с загрузкой ЦП (или любым другим показателем, который вы можете выбрать сами), в центре дерево методов со статистикой выполнения по времени и количеству вызовов, в нижней части просмотр исходного кода методов (если код доступен).
Здесь есть некоторая странность: мы видим, что суммарное время выполнения метода SampleBadSubMethod2 равно 14 мс, хотя внутри него задержка на 1 мс и он вызывается 10000 раз. Возможно, ANTS как-то некорректно обрабатывает метод Thread.Sleep.

Теперь снова «оптимизируем» приложение, запускаем профайлер, получаем результат и… не можем сравнить средствами ANTS… В FAQ на сайте предлагают запустить ещё один профайлер и переключаться между ними, сравнивая результат. Ну, спасибо, что ещё сказать :)

dotTrace

При выборе File->Profile появляется окно:

Выбираем тип приложения, задаём настройки и Run!
После запуска профайлинга появляется небольшое окно, с помощью которого можно получить результат (Get Snapshot) или завершить профайлинг.

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

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

Ну что ж, оптимизация удалась.

EQATEC Profiler

Запускаем профайлер, видим окно:

Здесь нужно выбрать путь до папки bin приложения, выбрать сборки, которые хотим исследовать на нажать Build.

Затем запускаем свой любимый браузер и загружаем страницу приложения. Если всё нормально, то в логе появится надпись Profiled appication xxx started и станут активными кнопки «Take snapshot» и «Reset counters»

Далее нажимаем «Take snapshot»:

А вот и наш snapshot:

Видим статистику вызовов, а также представление методов в виде блоков (в нижней части). Эти блоки кликабельны, т.е. можно переходить по иерархии вызовов вниз/вверх.
Теперь в очередной раз оптимизируем приложение и сравниваем результат:

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

На этом всё, посмотрим на сводную таблицу возможностей представленных профайлеров

Summary

VS Profiler ANTS dotTrace EQATEC
Показ относительных результатов выполнения методов (в %)
Показ абсолютных результатов выполнения методов (в секундах, мс и т.п.)
Показ числа вызовов методов
Просмотр исходников методов
Сравнение результатов двух замеров
Цена > 5000$ 1) от 395$ 2) от 199$ 3) бесплатно 4)

1) в составе VS Premium и выше
2) зависит от редакции
3) для open source проектов бесплатен
4) ограничение на 10 одновременно загружаемых dll, за $ с меньшими ограничениями

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

VS Profiler

встроен в VS (правда, в premium и ultimate)
взаимодействие с ADO.NET
капризный, иногда профайлинг не запускается без объяснения причин
секция appSettings должна быть в web.config, а не вынесена в отдельный файл, т.к. туда пишутся какие-то служебные настройки, а разработчики видимо не предусмотрели расположение данной секции во внешнем файле
на большом проекте и не очень мощной машине заметно подтормаживает

ANTS Profiler

самая подробная информация по вызовам методов, куча счетчиков производительности
в режиме профайла SQL думает, что кроме ./SQLEXPRESS серверов больше не существует :)
нет сравнения двух результатов замеров

dotTrace

больше всех понравилась документация
в режиме просмотра дерева какая-то каша из цифр, названий методов, сборок
не запустился в режиме IIS Application, хотя всё делал по хорошей документации.

EQATEC

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

Итак, сделаю, возможно, субъективный вывод. Мой выбор — EQATEC Profiler, для многих задач оценки производительности его более чем достаточно. Если у вас есть возможность использования VS Premium или Ultimate, встроенный профайлер достаточно неплохой продукт. В этом случае необходимость в покупке других профайлеров отпадёт. Из оставшихся двух профайлеров своей мощью поражает ANTS профайлер, хотя, конечно, почему нет сравнения результатов — непонятно. У dotTrace обилие вариантов приобретения с большим количеством возможностей самого профайлера.

Спасибо, что дочитали этот обзор! Надеюсь, он поможет вам сделать выбор.

Основы 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.NET: Обзор технологии

Written on 27 Декабря 2006 . Posted in ADO.NET и базы данных

ОГЛАВЛЕНИЕ

Cтремительное развитие веб приложений вызвало необходимость пересмотреть методы работы с источниками данных, лучше адаптировать их к специфики приложений. Непредсказуемый рост числа клиентов интернет сайтов заставляет разработчиков переходить от клиентсерверной к three-tier архитектуре, что часто порождает непреодолимые проблемы. Базы данных не способны поддерживать неограниченное число активных соединений, ограничивая доступность сайта и принося убытки. Брандмауэры могут препятствовать передаче двоичных данных между узлами. ADO.NET призвано решить эти и другие проблемы и вместе с тем сохранить удобство и простоту программирования.

Преимущества и нововведения в ADO.NET

Использование разъединенной модели доступа к данным.

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

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

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

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

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

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

Хранение данных в объектах DataSet.

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

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

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

Глубокая интеграция с XML.

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

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

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

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

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

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

Практическое применение ADO.NET

Введение.

Умение применить на практике теоритические знания преумножает их цену, поэтому мы посвящаем примерам работы с ADO.NET отдельный раздел, где рассмотрим наиболее типичные задачи, разбив их на отдельные блоки: соединение с источником данных, выборка, удаление и обновление информации, вывод содержимого на экран, работа с XML и т.д. В качестве платформы для построения интерфейса будет использована ASP.NET, а как язык программирования взят C#.

Managed Providers.

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, а разница заключается, в основном, в именовании.

Для работы с нашими примерами вам понадобится создать базу данных dotSITE и выполнить следующие скрипты для создания структуры и минимального наполнения.

Теперь, когда мы создали базу данных, можно переходить непосредственно к примерам. Во всех случаях, кроме особо оговоренных будет использоваться SQL Managed Provider.

Установление соединения с базой данных:

Чтобы установить соединение с нашейбазой данных следует выполнить следующий код:
Как видно, при использовании SQL Managed Provider не указывается DSN. Для работы с произвольной базой данных строка соединения указыается как в ADO. В этом случае используются ADO ориентированные классы: ADOConnection, ADOCommand, ADODataReaderи др.

Важно! Не забудьте импортировать соответствующие пространства имен в зависимости от используемого Managed Provider. В ASP.NET это будет выглядеть:

Выборка, удаление и обновление данных:

Для выполнения операций над базой данных используется класс SQLConnection. При его создании мы передаем строку, содержащую SQL скрипт и имя соединения. В нашем случае это будет:
После этого, если это операция выборки можно использовать Dataset для передачи в него данных:
Если же производилось удаление, обновление или вставка, то используется метод ExecuteNonQuery(). При этом также нужно открыть, а после выполнения действий закрыть соединение. Следующий фрагмент кода иллюстриркет это:
Теперь соберем все это вместе и продемонстрируем пример aspx страницы, выводящей на экран содержимое нашей базы данных. При этом используется серверный контрол DataGrid:
Последнее, что еще не было продемонстрировано — заполнение DataSet из XML файла:

Как видно, есть небольшие отличия от работы с DataSet, заполняемым из SQL БД, заключающиеся в основном в использовании FileStreamObject. Однако, на мой взгляд, текст достаточно прозрачен и не нуждается в комментариях.

ASP.NET, ADO.NET, Access database, ПРОБЛЕМА.

Есть база данных на Access.
хочу с помощью ASP.NET, ADO.NET вывести данные.
но почему -то не работает.
подскажите плиз если кто знает

11.11.2008, 02:55 11.11.2008, 10:41 2 11.11.2008, 14:37 [ТС] 3 11.11.2008, 16:39 4
11.11.2008, 16:39
14.11.2008, 02:19 [ТС] 5

на этот скрипт она выругалась так:

Could not find installable ISAM.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.OleDb.OleDbException: Could not find installable ISAM.

Line 6: protected void Page_Load(Object sender, EventArgs e) <
Line 7: OleDbConnection conn = new OleDbConnection(‘Prov > Line 8: conn.Open();
Line 9: OleDbDataAdapter adapter = new OleDbDataAdapter(‘select * from EmailBase’, conn);
Line 10:

16.11.2008, 10:07 6
16.11.2008, 13:27 [ТС] 7
16.11.2008, 15:03 8
16.11.2008, 15:08 9
16.11.2008, 15:55 [ТС] 10

OLEDB.5.0 тоже не пошло.

вот что написала:

No error information available: REGDB_E_CLASSNOTREG(0x80040154).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.OleDb.OleDbException: No error information available: REGDB_E_CLASSNOTREG(0x80040154).

Line 6: protected void Page_Load(Object sender, EventArgs e) <
Line 7: OleDbConnection conn = new OleDbConnection(‘Prov > Line 8: conn.Open();
Line 9: OleDbDataAdapter adapter = new OleDbDataAdapter(‘select * from EmailBase’, conn);
Line 10:

Source File: C:www2aspxaccessdb.aspx Line: 8

ЗЫ.
кстати, а если БД на mySQL, тогда для нее свои функции или как?

ADO.NET: Обзор технологии
Страница 3. Практическое применение ADO.NET

Практическое применение ADO.NET

Введение.

Умение применить на практике теоритические знания преумножает их цену, поэтому мы посвящаем примерам работы с ADO.NET отдельный раздел, где рассмотрим наиболее типичные задачи, разбив их на отдельные блоки: соединение с источником данных, выборка, удаление и обновление информации, вывод содержимого на экран, работа с XML и т.д. В качестве платформы для построения интерфейса будет использована ASP.NET, а как язык программирования взят C#.

Managed Providers.

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, а разница заключается, в основном, в именовании.

Для работы с нашими примерами вам понадобится создать базу данных dotSITE и выполнить следующие скрипты для создания структуры и минимального наполнения.

Теперь, когда мы создали базу данных, можно переходить непосредственно к примерам. Во всех случаях, кроме особо оговоренных будет использоваться SQL Managed Provider.

Установление соединения с базой данных:

Чтобы установить соединение с нашейбазой данных следует выполнить следующий код:
Как видно, при использовании SQL Managed Provider не указывается DSN. Для работы с произвольной базой данных строка соединения указыается как в ADO. В этом случае используются ADO ориентированные классы: ADOConnection, ADOCommand, ADODataReaderи др.

Важно! Не забудьте импортировать соответствующие пространства имен в зависимости от используемого Managed Provider. В ASP.NET это будет выглядеть:

Выборка, удаление и обновление данных:

Для выполнения операций над базой данных используется класс SQLConnection. При его создании мы передаем строку, содержащую SQL скрипт и имя соединения. В нашем случае это будет:
После этого, если это операция выборки можно использовать Dataset для передачи в него данных:
Если же производилось удаление, обновление или вставка, то используется метод ExecuteNonQuery(). При этом также нужно открыть, а после выполнения действий закрыть соединение. Следующий фрагмент кода иллюстриркет это:
Теперь соберем все это вместе и продемонстрируем пример aspx страницы, выводящей на экран содержимое нашей базы данных. При этом используется серверный контрол DataGrid:
Последнее, что еще не было продемонстрировано — заполнение DataSet из XML файла:

Как видно, есть небольшие отличия от работы с DataSet, заполняемым из SQL БД, заключающиеся в основном в использовании FileStreamObject. Однако, на мой взгляд, текст достаточно прозрачен и не нуждается в комментариях.

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