Реклама
Спонсорские ссылки
-
Статья
Версия для печати
Обсудить на форуме
ADO.NET Что такое соединение?



В предыдущей статье было упомянуто всего несколько слов о том, что в состав Провайдера Данных (Data Provider) входит объект Соединение (Connection). данной статье мы рассмотрим этот объект более подробно, выясним его роль в ADO.NET, основные свойства и методы.

Назначение объекта Connection -  поддерживать физическую связь между хранилищем данных и приложением .NET. Поскольку, как мы уже знаем, в составе ADO.NET имеется два Провайдера Данных, а каждый из них имеет собственную реализацию объекта Connection, нам придется рассмотреть обе разновидности.
   
OLE DB .NET Data Provider включает в себя OleDbConnection (пространство имен System.Data.OleDB), а SQL Server .NET Data Provider, соответственно, - SqlConnection (пространство имен System.Data.SqlClient). Хотя различия между ними не столь радикальны, тем не менее, их следует иметь в виду при переносе приложений на другое хранилище данных.
   
Как упоминалось ранее, SqlClient работает с хранилищем данных напрямую, поэтому при работе с Microsoft SQL Server 7.0 и выше предпочтительнее использовать SQL Server .NET Data Provider и SqlConnection, поскольку это обеспечит более высокую эффективность работы приложения.
   
Как создать соединение?

   
Те, кто работает в интерактивной среде разработки Visual Studio .NET, наверное, уже привыкли к тому, что в ней имеется большой набор "мастеров", которые облегчают труд программиста, выполняя за него обременительную рутинную работу. Не является исключением и создание Connection.
   
Те, кто проповедует аскетизм .NET Framework (или вынужден довольствоваться им поневоле), могут пропустить этот раздел и перейти к следующему, в котором описывается программное создание Connection.
   
Создание Connection посредством Server Explorer

   
В состав Visual Studio .NET входит весьма ценный инструмент - Server Explorer, который позволяет во время разработки устанавливать соединения с различными службами, включая журналы, очереди сообщений и т.д., а также с источниками данных, что сейчас представляет для нас наибольший интерес.
   
Попробуем создать Соединение при помощи Server Explorer. Для этого сначала создадим проект приложения Windows. Затем убедимся, что панель Server Explorer доступна (если нет, включить ее можно посредством меню View ->Server Explorer). Выглядит она примерно таким образом:


Далее нажимаем кнопку "Connect to Database", которая находится в верхней части панели Server Explorer:


Такая же кнопка имеется в меню Tools:


После нажатия на кнопку появляется окно "Свойства связи с данными", хорошо знакомое тем, кто уже имеет опыт работы в ADO:


Попробуем создать соединение с базой данных "Борей", которая поставляется в качестве примера вместе с Microsoft Access различных версий и наверняка присутствует на подавляющем большинстве компьютеров, на которых установлен Microsoft Office. Для этого:
   
  • переходим на страницу "Поставщик данных";
  • выбираем из списка "Поставщики OLE DB" строку "Microsoft Jet 4.0 OLE DB Provider"

Примечание. Microsoft Jet - это ядро базы данных, которое Microsoft использует как основу для Access, а также в составе ряда других продуктов (например, для хранения электронной корреспонденции в Exchange Server). С помощью провайдера Microsoft Jet 4.0 OLE DB Provider можно получить доступ к данным, хранящимся в базах данных, созданных посредством Access.


  • жмем кнопку "Далее" >> или переходим на страницу "Подключение";
  • нажав на кнопку с многоточием "...", выбираем полный путь к файлу базы данных (или вводим вручную, если есть желание); у меня он выглядит так: C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb;
  • если на вашей системе база данных "Борей" защищена паролем, введите его в соответствующем поле; если вы желаете, чтобы пароль для доступа к базе данных хранился месте с другими данными о соединении, установите опцию "Разрешить сохранение пароля" (разумеется, это нежелательно, если содержимое базы не должно быть открыть для несанкционированного доступа);



  • для проверки работоспособности нажмите кнопку "Проверить подключение"; если все сделано правильно, вы увидите результат:
       


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


В этом случае проверьте правильность введенного пути к файлу базы данных и, возможно, уточните пароль; 
  • если проверка подключения к базе данных прошла успешно, нажмите кнопку "OK" окна "Свойства связи с данными";
  • на панели Server Explorer появляется новое соединение с базой данных "Борей":



Посредством Server Explorer мы можем не только исследовать структуру таблиц, видов, хранимых процедур и прочих объектов базы данных, но и получить доступ к их содержимому. Например, двойной щелчок левой кнопкой мыши на значке таблицы открывает ее содержимое для просмотра и даже редактирования в среде Visual Studio .NET.

  • теперь осталось создать объект Connection, который позволит нашей программе установить соединение с базой данных "Борей"; для этого буксируем пиктограмму соединения с панели Server Explorer на форму нашего приложения.

На этом работа по созданию объекта Connection завершена! Под формой приложения появился значок:
   


Это и есть объект типа System.Data.OleDb.OleDbConnection, который мы стремились получить. При необходимости имя объекта можно изменить при помощи панели свойств.
   
Обратите особое внимание на то, что соединение, созданное посредством Server Explorer, не является частью текущего проекта, а хранится вместе с настройками среды Visual Studio .NET. На мой взгляд, это имеет как положительные, так и отрицательные стороны.
   
К положительным сторонам относится то, что соединение может быть использовано во множестве проектов. К отрицательным - то, что, поскольку соединение не является частью проекта, то при его передаче кому-нибудь другому или при продолжении работы над ним на другом компьютере информация о настройке соединения передана не будет.
   
Итак, подведем итог проделанной работе. В результате наших действий на панели Server Explorer появилось соединение с базой данных "Борей", которое посредством буксировки мышью было помещено на форму нашего приложения. Появилась соответствующая пиктограмма, при ее выборе мышью свойства объекта Connection видны на панели свойств Проверка кода программы показывает, что среди объектов формы появился новый

Код:
private System.Data.OleDb.OleDbConnection oleDbConnection1;
   
а в методе InitializeComponent появились строки:
Код:
this.oleDbConnection1 = new System.Data.OleDb.OleDbConnection();
     
//
     
// oleDbConnection1
     
//
     
this.oleDbConnection1.ConnectionString =
@"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";User ID=Admin;Data
Source=C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb;Mode=Share
Deny None;Extended Properties="""";Jet OLEDB:System database="""";Jet
OLEDB:Registry Path="""";Jet OLEDB:Database Password="""";Jet OLEDB:Engine
Type=5;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk
Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database
Password="""";Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt
Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact
Without Replica Repair=False;Jet OLEDB:SFP=False";

Мы видим, что помимо создания объекта OleDbConnection, его свойству ConnectionString присвоено значение в видедовольно-такидлинной строки. Что означает сия конструкция, мы разберем немного позже, а пока рассмотрим альтернативные способы создания объекта Connection.

Примечание. Для полноты изложения стоит упомянуть, что помимо панели Server Explorer, с Connection можно также работать и посредством ссылок на базу даннах (Database References) из панели Solution Explorer Visual Studio .NET. Однако подробно на этом останавливаться не будем, поскольку этот вопрос скорее относится к работе IDE, а не к функциональности Connection ADO.NET.
   
Программное создание Connection

   
Разумеется, как и практически любой объект в Visual Studio .NET, создаваемый посредством вызова "мастера", экземпляр объекта Connection можно создать и программным путем. Особенно полезным такой способ является при создании консольных приложений .NET, поскольку "мастер" создает экземпляр Connection при буксировании его на форму приложения, а отсутствие самой формы делает такой подход непригодным.

Вряд ли для читателя будет неожиданностью, что для создания Connection нужно вызвать конструктор. Обе разновидности Connection имеют два перегруженных варианта конструктора: с пустым списком параметров () и с единственным параметром (ConnectionString), который задает строку подключения (и опять откладываем разъяснение, что же это такое).
   
Пример программного создания Connection:
Код:
public SqlConnection cnnTest = new SqlConnection();
   
(разумеется, предполагается, что в программе предварительно было объявлено, что используется пространство имен System.Data.SqlClient).
   
Свойства Connection

   
Прежде всего во избежание возможных недоразумений замечу, что при рассмотрении свойств, методов и событий я рассматриваю в первую очередь те, которые являются собственными для данного класса (это относится к Connection и будет относиться к классам, рассматриваемым в следующих статьях). Помимо них, классы имеют свойства, методы и события, унаследованные от родительских классов. Если унаследованные члены класса не имеют непосредственного отношения к нашей основной тематике, а именно - работе с базами данных посредством ADO.NET, я их рассматривать не буду, чтобы не загромождать статью несущественными деталями. В то же время имейте в виду, что данные классы могут иметь и другие члены, кроме упомянутых мной.
   
Для управления соединением с источником данных из программы объект Connection, разумеется, имеет набор свойств и методов.
Рассмотрим подробнее свойства обеих реализаций объекта.
   
   
НазваниеОписаниеТипДоступOLE DBSQLЗначение по умолчанию
ConnectionStringСтрока соединенияSystem.StringRW++
ConnectionTimeoutВремя ожидания соединения в секундахSystem.Int32R++15 сек
DatabaseИмя текущей базы данных (или той, которая будет использоваться при открытии соединения)System.StringR++
DataSourceИмя сервера баз данных (SQL) или спецификация файла с даннымиSystem.StringR++
PacketSizeРазмер сетевого пакета в байтахSystem.Int32R-+8192
ProviderИмя провайдера OLE DBSystem.StringR+-
ServerVersionВерсия сервера баз данныхSystem.StringR++
StateБитовая комбинация значений ConnectionStateConnectionStateR++Closed
WorkstationIdСтрока, идентифицирующая клиентаSystem.StringR-+Имя клиентского компьютера
     
Примечания:
  • В графе "Доступ RW" обозначает запись и чтение, R - только чтение.
  • В графах "OLE DB" и "SQL" указано наличие данного свойства для OleDbConnection и SqlConnection, соответственно. "+" - свойство поддерживается, "-" - не поддерживается.
  • В графе "Значение" по умолчанию прочерк "-" для свойств типа System.String означает пустую строку.
  • Перечислены только собственные свойства объекта, без учета свойств, наследуемых от Component.

Те, кто знаком с классическим ADO, наверное, удивятся, заметив, что все свойства, кроме ConnectionString, отныне доступны только для чтения. Да, это действительно так. Все параметры соединения в ADO.NET задаются исключительно через строку соединения. Возможно, это и к лучшему, поскольку пропадает соблазн попытаться их изменить во время выполнения программы, что зачастую приводит к исключительной ситуации при открытом соединении.
   
Обратите внимание на небольшое различие в свойствах OleDbConnection и SqlConnection. Хотя основной набор их одинаков, все же некоторые специфичны для провайдера. SqlConnection имеет уникальные свойства PacketSize и WorkstationId, а OleDbConnection - свойство Provider. Это может негативно повлиять на переносимость программ на другую платформу.
   
Следует избегать задания свойству ConnectionTimeout
      нулевого значения, т.к. оно соответствует бесконечному тайм-ауту и может
      привести к зависанию приложения.
   
Значение свойства Database может изменяться в ходе выполнения приложения, если оно меняет текущую базу данных (либо соответствующим оператором SQL, либо вызовом метода ChangeDatabase).
   
Значение свойства PacketSize может быть задано в диапазоне от 512 до 32767 байт. При пересылке больших объемов данных увеличение размера пакета может повысить производительность, т.к. уменьшает количество небходимых операций чтения/записи пакетов.
   
Свойство State может принимать значения из перечисления ConnectionState. Эти значения следующие:
   
BrokenСоединение с источником данных прервано. Соединение может быть закрыто и установлено заново. (Зарезервировано для будущих версий).
ClosedСоединение закрыто
ConnectingСоединение с источником данных устанавливается. (Зарезервировано для будущих версий).
ExecutingСоединение выполняет команду. (Зарезервировано для будущих версий).
FetchingСоединение занято передачей данных. (Зарезервировано для будущих версий).
OpenСоединение открыто
     
В данное время из этого набора значений допустимыми являются только Open и Closed.
   
Строка соединения (Connection String)

   
Наконец-то пришла пора рассказать о том, что же такое представляет собой строка соединения. Этот термин уже упоминался ранее. Однако предмет достаточно сложен и должен быть рассмотрен подробнее.
   
Свойство ConnectionString является, пожалуй, основным свойством Connection. Все остальные свойства, как мы видели ранее, доступны только на чтение и передают значение одного из параметров, задаваемых в строке соединения.
   
Строка соединения представляет собой текстовую строку специального вида. Она состоит из пар вида ключ=значение, разделенных символом "точка с запятой" (;).
   
"Ключ" не зависит от регистра и может задаваться как на верхнем, так и на нижнем регистрах; "значение" в общем случае зависит от регистра.
   
Допустимо повторение "ключа" несколько раз в строке. В этом случае используется последнее вхождение, остальные игнорируются. Ошибкой такое повторение не является.
   
Содержимое строки специфично для конкретного провайдера. Обычно для построения корректной строки во время проектирования программы полезно бывает воспользоваться следующей уловкой: создать соединение при помощи Server Explorer (мы уже умеем это), а затем скопировать строку соединения из его свойств.
   
Значение свойства ConnectionString можно задавать только при закрытом соединении! После установки Connection анализирует строку и устанавливает значения остальных свойств в соответствии с ее содержимым. Впрочем, полный анализ содержимого строки соединения производится только в момент открытия Connection. Если при этом встретится неподдерживаемое имя ключа или недопустимое значение, будет сгенерировано соответствующее исключение (OleDbException или SqlDbException).
   
Объект Connection реализует интерфейс IDbConnection, поэтому для доступа к общим свойствам обоих провайдеров можно объявить переменную типа IDbConnection. Это позволит немного смягчить проблему неполной совместимости двух провайдеров данных.
   
Методы Connection

   
К счастью, методы SqlConnection и OleDbConnection совершенно одинаковы.
BeginTransactionНачинает транзакцию
ChangeDatabaseПозволяет изменить текущую базу данных при открытом соединении
CloseЗакрывает соединение с источником данных
CreateCommandСоздает объект DataCommand, связанный с источником данных, и возвращает его как результат функции
OpenУстанавливает соединение с источником данных
   
Наиболее важными, пожалуй, являются Open и Close. Они могут вызываться как явно, так и неявно, другими компонентами ADO.NET. Если метод Open вызывается компонентами DataAdapter или DataCommand (которые мы рассмотрим в следующих статьях), то они оставляют Connection в начальном состоянии, т.е. если Connection был открыт, то ничего не меняется, а если закрыт - то вызывающий компонент открывает его, выполняет требуемую операцию, а затем закрывает. Таким образом, программист может игнорировать побочные эффекты этих компонентов.
   
Открытое соединение не закрывается автоматически при уничтожении объекта Connection! Необходимо помнить, что открытое соединение потребляет ресурсы как рабочей станции, так и сервера-источника данных. Поэтому следует взять за правило явно закрывать соединение посредством вызова Close и делать это как можно раньше, как только соединение больше не требуется. При закрытии соединения Close откатывает все незавершенные транзакции.
   
BeginTransaction - перегруженная функция,
      возвращающая объект-транзакцию (различные для разных провайдеров). Думаю, сейчас обсуждать вопрос реализации транзакций преждевременно, поскольку в теоретическом курсе мы еще не рассмотрели, что это такое.
   
CreateCommand создает объект Datacommand, который мы еще не рассматривали. Поэтому нам придется пока довольствоваться этим скудным описанием. Смысл данной операции станет ясен позже.
   
Пул соединений

   
Для более экономного использования ресурсов ADO.NET работает с пулом соединений. SQL Server .NET Data Provider имеет собственный пул соединений, а OLE DB .NET Data Provider использует пул OLE DB. Управлять пулом можно соответствующими параметрами строки соединения, но подробное рассмотрение этого вопроса выходит за рамки статьи.
   
Для начала достаточно знать, что пул соединений - это некое хранилище готовых к употреблению соединений. По умолчанию пул соединений разрешен, и при закрытии соединения через Close оно на самом деле не закрывается физически, а помещается в пул. Если при попытке открыть новое соединение через Open обнаруживается, что такое готовое соединение есть в пуле, оно не создается, а просто выдается приложению из пула. Поскольку на установление соединения требуется время, которое для удаленного сервера может оказаться весьма ощутимым, использование пула может существенно ускорить работу приложения.
   
Механизм работы с пулом соединений совершенно прозрачен для программиста, и запрещение пула или явное управление его параметрами через строку соединения вряд ли потребуется для повседневной работы.
   
События connection

   
Эти события немногочисленны, их всего два, и они совпадают для боих вариантов Connection.
   
 StateChange возникает при изменении состояния Connection, т.е. когда его свойство State меняет значение с Open на Closed или наоборот. Обработчик этого события получает аргумент типа StateChangeEventArgs, который имеет два свойства: OriginalState (исходное состояние соединения) и CurrentState (его текущее состояние). Оба эти свойства могут принимать одно из значений перечисления ConnectionState, которое мы уже рассмотрели ранее при изучении свойства State.
   
InfoMessage возникает, когда источник данных возвращает предупреждение или информационное сообщение. Оба варианта соединения возвращают коллекцию ошибок, текстовое описание ошибки и имя объекта, в котором возникла ошибка. OleDbConnection.InfoMessage имеет дополнительное свойство ErrorCode, которое идентифицирует источник ошибки в соответствии со стандартом ANSI SQL.
   
Итоги

   
Итак, подведем итог, чему мы научились в этой статье.
   
Прежде всего - весьма, на мой взгляд, важный факт, про который не следует забывать. Имеется две реализации Connection - для OLE DB и MS SQL Server. Эти реализации довольно похожи, но не идентичны. Поэтому на начальном этапе разработки следует определиться, чем пожертвовать - эффективностью или переносимостью, так как в дальнейшем может потребоваться переделка программы.
   
Объект Connection необходим для установления связи с источником данных. Другие объекты используют Connection для обмена информацией с источником данных, при этом некоторые из них требуют, чтобы соединение было явно открыто, другие способны управлять его состоянием самостоятельно.
   
Если разрабатывается типичное приложение на основе диалога, создать соединение можно как вручную, так и воспользоваться услугами специального мастера. При разработке консольного приложения выбора не остается - только создание программного соединения вручную, т.к. при работе мастера соединение буксируется на форму приложения.
   
Основное свойство Connection - это ConnectionString,- именно в нем задаются все параметры, необходимые для установления соединения. Все остальные свойства, кроме State, являются производными и возвращают значения отдельных параметров соединения, но изменять их можно только через ConnectionString.
   
Задать корректное значение ConnectionString - задача не из легких. Неоценимую помощь в ее формировании может оказать мастер установки соединений, даже если само соединение планируется устанавливать программно.
   
Любые изменения параметров соединения можно производить только тогда, когда оно закрыто. Исключением является текущая база данных, которую можно изменить при открытом соединении вызовом метода ChangeDatabase.
   
При изменении состояния соединения возникает событие StateChange, а при получении предупреждения или информационного сообщения - событие InfoMessage.
   
Заключение

   
И наконец в закрепление знаний, полученных нами о соединениях ADO.NET, приведу небольшую программу, которая способна открывать и закрывать соединения с учебной базой данных (кнопки "Open" <OPEN> и "Close" <CLOSE>), а также показывать состояние и свойства соединения (кнопка "Show" <SHOW>). Программа может быть откомпилирована и выполнена в среде Visual Studio .NET или .NET Framework.
   
При выполнении программы на вашем компьютере обратите внимание на следующие моменты, которые, на мой взгляд, наиболее наглядны:
  • Попытка открыть уже открытое соединение приводит к ошибке. Поэтому при открытии соединения в сомнительных случаях либо проверяйте его состояние (свойство State), либо перехватывайте исключение InvalidOperationException. К закрытию закрытого соединения ADO.NET относится гораздо лояльнее и ошибки времени выполнения не возникает.
  • Не все свойства Connection доступны при закрытом соединении, в чем вы можете убедиться, нажав кнопку <SHOW>при закрытом соединении. Впрочем, вряд ли кому-то понадобятся свойства закрытого соединения.

Код программы-примера для этой статьи:

Код:
using System;
using System.Windows.Forms;
using System.Data;
       
namespace ConnSample
{
   public class frmConnSample : System.Windows.Forms.Form
  {
         private System.Windows.Forms.Button btnExit;
         private System.Windows.Forms.Button btnOpen;
         private System.Windows.Forms.Button btnClose;
         private System.Windows.Forms.Label lblConnState;
         private System.Windows.Forms.TextBox txtConnstate;
         private System.Data.OleDb.OleDbConnection oleDbCnn1;
         private System.Windows.Forms.Button btnShow;
         private System.Windows.Forms.ListBox lstConnProps;
         private System.ComponentModel.Container components = null;
       
         public frmConnSample()
         {
             InitializeComponent();
         }
       
       
         protected override void Dispose( bool disposing
        )
         {
          if( disposing )
          {
              if (components != null)
              {
                   components.Dispose();
               }

          }
          base.Dispose( disposing );
         }
       
         #region Windows Form Designer generated code
         private void InitializeComponent()
         {
             this.btnExit = new
             System.Windows.Forms.Button();
             this.oleDbCnn1 = new
             System.Data.OleDb.OleDbConnection();
             this.btnOpen = new
             System.Windows.Forms.Button();
             this.btnClose = new
             System.Windows.Forms.Button();
             this.lblConnState = new
             System.Windows.Forms.Label();
             this.txtConnstate = new
             System.Windows.Forms.TextBox();
             this.btnShow = new
             System.Windows.Forms.Button();
             this.lstConnProps = new
             System.Windows.Forms.ListBox();
             this.SuspendLayout();
         //
         // btnExit
         //
             this.btnExit.Location = new
             System.Drawing.Point(296, 232);
             this.btnExit.Name = "btnExit";
             this.btnExit.TabIndex = 0;
             this.btnExit.Text = "Exit";
             this.btnExit.Click += new
             System.EventHandler(this.btnExit_Click);
         //
         // oleDbCnn1
         //
         // строка подключения; подкорректируйте ее
         // согласно размещению файлов на вашем компьютере
             this.oleDbCnn1.ConnectionString =
            @"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";User ID=Admin;Data
            Source=C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb";
         // добавляем обработчик события StateChange
             this.oleDbCnn1.StateChange += new
             System.Data.StateChangeEventHandler(this.ShowConnState);
         //
         // btnOpen
         //
            this.btnOpen.Location = new
            System.Drawing.Point(16, 232);
            this.btnOpen.Name = "btnOpen";
            this.btnOpen.TabIndex = 2;
            this.btnOpen.Text = "Open";
            this.btnOpen.Click += new
            System.EventHandler(this.btnOpen_Click);
         //
         // btnClose
         //
         this.btnClose.Location = new
         System.Drawing.Point(104, 232);
         this.btnClose.Name = "btnClose";
         this.btnClose.TabIndex = 3;
         this.btnClose.Text = "Close";
         this.btnClose.Click += new
         System.EventHandler(this.btnClose_Click);
         //
         // lblConnState
         //
         this.lblConnState.Location = new
         System.Drawing.Point(16, 200);
         this.lblConnState.Name = "lblConnState";
         this.lblConnState.Size = new
         System.Drawing.Size(96, 16);
         this.lblConnState.TabIndex = 4;
         this.lblConnState.Text = "Connection state:";
         //
         // txtConnstate
         //
         this.txtConnstate.Location = new
         System.Drawing.Point(112, 200);
         this.txtConnstate.Name = "txtConnstate";
         this.txtConnstate.TabIndex = 5;
         this.txtConnstate.Text = "";
         //
         // btnShow
         //
         this.btnShow.Location = new
         System.Drawing.Point(296, 200);
         this.btnShow.Name = "btnShow";
         this.btnShow.TabIndex = 6;
         this.btnShow.Text = "Show";
         this.btnShow.Click += new
         System.EventHandler(this.btnShow_Click);
         //
         // lstConnProps
         //
         this.lstConnProps.Location = new
         System.Drawing.Point(16, 16);
         this.lstConnProps.Name = "lstConnProps";
         this.lstConnProps.Size = new
         System.Drawing.Size(344, 173);
         this.lstConnProps.TabIndex = 7;
         //
         // frmConnSample
         //
         this.AutoScaleBaseSize = new
         System.Drawing.Size(5, 13);
         this.ClientSize = new System.Drawing.Size(384,  266);
         this.Controls.AddRange(new
         System.Windows.Forms.Control[]
       
         {
            this.lstConnProps,
            this.btnShow,
            this.txtConnstate,
            this.lblConnState,
            this.btnClose,
            this.btnOpen,
            this.btnExit
         } );
            this.FormBorderStyle =
           System.Windows.Forms.FormBorderStyle.Fixed3D;
           this.MaximizeBox = false;
           this.MinimizeBox = false;
           this.Name = "frmConnSample";
           this.Text = "Connection Sample";
           this.ResumeLayout(false);
         }
         #endregion
       
         [STAThread]
         static void Main()
         {
            Application.Run(new frmConnSample());
         }
       
         private void btnExit_Click(object sender, System.EventArgs e)
         {
            Application.Exit();
         }
       
         private void btnOpen_Click(object sender, System.EventArgs e)
         {
            try
           {
               oleDbCnn1.Open();
           }
            catch (InvalidOperationException err) // попытка открыть уже открытое соединение
           {
               MessageBox.Show("Connection is already open!!!", "Error",
                                             MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (System.Data.OleDb.OleDbException err)
            {
                MessageBox.Show("Error opening  Connection!!!", "Error",
                                             MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
         }
       
         private void btnClose_Click(object sender, System.EventArgs e)
         {
             oleDbCnn1.Close();
         }
       
         private void btnShow_Click(object sender, System.EventArgs e)
         {
             try
            {
                lstConnProps.Items.Clear();         
                lstConnProps.Items.Add("ConnectionString = " + oleDbCnn1.ConnectionString);
                lstConnProps.Items.Add("ConnectionTimeout = " + oleDbCnn1.ConnectionTimeout.ToString());
                lstConnProps.Items.Add("Database = "
        + oleDbCnn1.Database);
               lstConnProps.Items.Add("DataSource =
        " + oleDbCnn1.DataSource);
               lstConnProps.Items.Add("Provider = "
        + oleDbCnn1.Provider);
         
               lstConnProps.Items.Add("ServerVersion = " + oleDbCnn1.ServerVersion);
               lstConnProps.Items.Add("State = " +
        oleDbCnn1.State);
         }
             catch (System.InvalidOperationException err)
            {
                MessageBox.Show("Cannot get some properties of the closed Connection!!!",
                                             "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
       
         // индикатор текущего состояния соединения
         private void ShowConnState(object sender, StateChangeEventArgs e)
         {
             txtConnstate.Text = oleDbCnn1.State.ToString();
         }
    }
}
   
Исправляя свою оплошность, на которую справедливо указали читатели, привожу здесь источники информации, которые были использованы при подготовке статьи.

При изложении в основном я придерживался последовательности, принятой в книге "ADO.NET step by step" (она у меня имеется в электронном варианте; откуда она взялась, не помню. Если ее нет в нашей библиотеке, могу выслать файл). Мне книга очень понравилась, настоятельно рекомендую по возможности ознакомиться с ней.

Кроме того, я изучил раздел "Доступ к данным при помощи ADO.NET" книги Эндрю Троелсена "C# и платформа .NET". На мой взгляд, для самостоятельного изучения ADO.NET этот материал малопригоден, поскольку состоит почти исключительно из перечисления методов и свойств оъектов с весьма скудными примерами их использования.

И, конечно же, источником детальной информации, как всегда, служил MSDN.

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