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


Содержание

ADO.NET. Элементы теории

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

Модели «клиент-сервер» в технологии баз данных

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

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

  • функции ввода и отображения данных (Presentation Logic);
  • прикладные функции, определяющие основные алгоритмы решения задач приложения (Business Logic);
  • функции обработки данных внутри приложения (Database Logic);
  • функции управления информационными ресурсами (Database Manager System);
  • служебные функции, играющие роль связок между функциями первых четырех групп.

Двухуровневые модели

Двухуровневые модели фактически являются результатом распределения пяти указанных функций между двумя процессами, которые выполняются на двух платформах: на клиенте и на сервере. В чистом виде почти никакая модель не существует, однако рассмотрим наиболее характерные особенности каждой двухуровневой модели.
1) Модель удаленного управления данными. Модель файлового сервера (File Server). В этой модели презентационная логика и бизнес-логика располагаются на клиенте. На сервере располагаются файлы с данными и поддерживается доступ к файлам. Функции управления информационными ресурсами в этой модели находятся на клиенте.
2) Модель удаленного доступа к данным (Remote Data Access). В ней база данных хранится на сервере. На сервере же находится ядро СУБД. На клиенте располагается презентационная логика и бизнес-логика приложения. Клиент обращается к серверу с запросами, например, на языке SQL.
3) Модель сервера баз данных. В этой модели бизнес-логика разделена между клиентом и сервером. На сервере бизнес-логика реализована в виде хранимых процедур — специальных программных модулей, которые хранятся в БД и управляются непосредственно СУБД. Клиентское приложение обращается к серверу с командой запуска хранимой процедуры, а сервер выполняет эту процедуру и регистрирует все изменения в БД, которые в ней предусмотрены. Сервер возвращает клиенту данные, релевантные его запросу, которые требуются клиенту либо для вывода на экран, либо для выполнения части бизнес-логики, которая расположена на клиенте. Трафик обмена информацией между клиентом и сервером резко уменьшается. Централизованный контроль в модели сервера баз данных выполняется с использованием механизма триггеров. Триггеры также являются частью БД.

Трехуровневая модель сервера приложений

Эта модель является расширением двухуровневой модели и в ней вводится дополнительный промежуточный уровень между клиентом и сервером. Этот промежуточный уровень содержит один или несколько серверов приложений. В этой модели компоненты приложения делятся между тремя исполнителями:
1) Клиент обеспечивает логику представления, включая графический пользовательский интерфейс, локальные редакторы; клиент может запускать локальный код приложения клиента, который может содержать обращения к локальной БД, расположенной на компьютере-клиенте. Клиент исполняет коммуникационные функции front-end части приложения, которые обеспечивают доступ клиенту в локальную или глобальную сеть. Дополнительно реализация взаимодействия между клиентом и сервером может включать в себя управление распределенными транзакциями.
2) Серверы приложений составляют новый промежуточный уровень архитектуры. Они спроектированы как для исполнения общих незагружаемых функций клиентов. Серверы приложений поддерживают функции клиентов как частей взаимодействующих рабочих групп, поддерживают сетевую доменную операционную среду, хранят и исполняют наиболее общие правила бизнес-логики, поддерживают каталоги с данными, обеспечивают обмен сообщениями и поддержку запросов, особенно в распределенных транзакциях.
3) Серверы баз данных в этой модели занимаются исключительно функциями СУБД: обеспечивают функции создания и ведения БД, поддерживают целостность реляционной БД, обеспечивают функции хранилищ данных (Warehouse services). Кроме того, на них возлагаются функции создания резервных копий БД и восстановления БД после сбоев и управления выполнением транзакций.

Отметим, что эта модель обладает большей гибкостью, чем двухуровневые модели. Наиболее заметны преимущества модели сервера приложений в тех случаях, когда клиенты выполняют сложные аналитические расчеты над базой данных, которые относятся к области OLAP-приложений (On-line analytical processing). В этой модели большая часть бизнес-логики клиента изолирована от возможностей встроенного SQL, реализованного в конкретной СУБД, и может быть выполнена на стандартных языках программирования. Это повышает переносимость системы и ее масштабируемость.

Архитектура ADO.NET

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

Платформа .NET определяет ряд пространств имен, позволяющих непосредственно взаимодействовать с локальными и удаленными базами данных (БД). Вместе они известны как ADO.NET.

Мы рассмотрим два уровня работы с ADO.NET:
подключенный уровень (connected layer) — позволяет взаимодействовать с базой данных с помощью объектов подключения, чтения данных и команд конкретного поставщика данных;
отключенный уровень (disconnected layer) — позволяет смоделировать в оперативной памяти данные из базы данных с помощью многочисленных классов из пространства имен System.Data (DataSet, DataTable и т.д.)
Существует и третья возможность взаимодействия с базами данных через объектную модель C#, с помощью ORM-фреймворка Entity Framework 4.0, которую мы пока рассматривать не будем.

Пространство имен System.Data

ADO.NET поставляется с тремя пространствами имен клиента базы данных: одно для SQL Server; второе — для любой базы данных, доступной через OLE DB; третье — для источников данных Open Database Connectivity (ODBC) . Если выбрана база данных, отличная от SQL Server, то отдают предпочтение OLE DB, если только не окажется, что нет другого выбора кроме ODBC. Если же в качестве базы данных используется Oracle, то на сайте Oracle .NET Developer можно получить их поставщика .NET — ODP.NET.

С точки зрения программиста, тело ADO.NET составляет базовая сборка с именем System.Data.dll. В этом двоичном файле находятся пространства имен, которые представляют типы конкретного поставщика данных ADO.NET, это: Odbs < >, OleDb < >, SqlClient < >, и кроме того: Common < >, Sql < >, SqlTypes < >и другие.
Большинство шаблонов проектов Visual Studio автоматически ссылаются на эту ключевую библиотеку System.Data < >доступа к данным. Однако для импорта нужных пространств имен необходимо изменить кодовые файлы, например:

Учтите также, что кроме System.Data.dll, существуют и другие ориентированные на ADO.NET сборки (например, System.Data.OracleClient.dll или System.Data.Entity.dll), которые необходимо вручную указывать в текущем проекте с помощью диалогового окна Add Reference (Добавление ссылки).

Компоненты ADO.NET

Двумя основными компонентами ADO.NET для доступа к данным и их обработки являются поставщики данных .NET Framework и DataSet.

Поставщики данных .NET Framework

— это компоненты, которые специально сконструированы для обработки данных и быстрого, однопроходного доступа к данным только для чтения:

  1. Объект Connection обеспечивает подключение к источнику данных.
  2. Объект Command позволяет обращаться к командам базы данных для возврата данных, изменения данных, выполнения хранимых процедур и передачи или получения сведений о параметрах.
  3. DataReader обеспечивает высокопроизводительный поток данных из источника данных.
  4. DataAdapter предоставляет «мост» между объектом DataSet и источником данных. DataAdapter использует объекты Command для выполнения команд SQL на источнике данных для загрузки DataSet с данными и согласования изменений данных, выполненных в DataSet, вновь с источником данных.
  5. Parameter представляет именованный параметр в параметризованном запросе.
  6. Transaction инкапсулирует транзакцию в базе данных.

Конкретные имена этих основных классов различаются у различных поставщиков (например, SqlConnection, OleDbConnection, OdbcConnection и MySqlConnection), но все эти объекты порождены от одного и того же базового класса (в случае объектов подключения это DbConnection), который реализует идентичные интерфейсы (вроде IDbConnection). Поэтому если вы научитесь работать с одним поставщиком данных, то легко справитесь и с остальными.

Класс DataSet в ADO.NET

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

ADO.NET

Введение.

Сегодняшний век высоких технологий и научных достижений диктует высокий темп развития всех отраслей и наук, что привело к автоматизации большинства сфер жизни современного человека. Как у и любого процесса у автоматизации есть и положительные и отрицательные стороны. Одну из этих сторон, а именно упрощает ли автоматизация трудовую деятельность людей, рассмотрим в дальнейшем подробней. С точки зрения любого руководителя автоматизация уменьшает издержки на производство и повышает эффективность работоспособности всей организации в целом. Но с точки зрения людей, которые разрабатывают системы автоматизации ситуация достаточно сложна, так как в основе любой информационной системы лежит база данных, а точнее СУБД. И выбор той или иной СУБД будет влиять на дальнейшие функциональные возможности информационной системы и то, как она будет спроектирована. А на сегодняшний день насчитывается около двух десятков различных СУБД. И перед разработчиком стает сложный выбор, какаю СУБД использовать. А знать особенности проектирования при каждой СУБД непосильная задача даже для целого отдела разработчиков.

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

То есть, еще возникает проблема не соответствия обработки информации большинством СУБД и способом обработки информации различными языками программирования.

Решение выдвинутых проблем найдено в новой технологии ADO.NET, разработанной компанией Microsoft, и включенной в их новую платформу .NET Framework.

Цели и задачи

Все проектировщики информационных систем подвержены одной большой проблеме: сложность выбора СУБД и дальнейшая реализация взаимодействия с ней. В связи с этим, целью данной работы является упрощение процесса проектирования ИС. Для реализации данной цели поставлена задача — разработать архитектуру, которая обладает возможностью масштабирования, адаптации к любому источнику данных. Архитектура должна быть проста в понимании разработчикам ИС, и обладать гибким механизмом использования ресурсов. Для реализации данной системы предлагается использовать технологию ADO.NET и платформы .NET.

ADO.NET

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

В NET Framework библиотеки ADO.NET находится в пространстве имени System.Data. Эти библиотеки обеспечивают подключение к источникам данных, выполнении команд, а также хранилище, обработку и выборку данных (рис 1.2).

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

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

Важным элементом автономного доступа к данным является контейнер для табличных данных, который не знает о СУБД. Такой незнающий о СУБД автономный контейнер для табличных данных представлен в библиотеках ADO.NET классом DataSet или DataTable.

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

Хотя ADO.NET и ADO — это полностью различные архитектуры доступа к данным.

Объекты ADO.NET

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

Архитектуру ADO.Net можно разделить на две фундаментальные части: подключаемую и автономную. Все классы в ADO.NET можно поделить по этому критерию. Единственное исключение — класс DataAdapter, который является посредником между подключенной и автономной частями ADO.Net.

Поставщики данных .NET

Подключаемая часть ADO.Net представляет собой набор объектов подключений.

Объекты подключений разделяются в ADO.NET по конкретным реализациям для различных СУБД. То есть для подключения к базе данных SQL SERVER имеется специальных класс SqlConnection.

Эти отдельные реализации для конкретных СУБД называются поставщиками данных .NET

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

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

Подключаемые классы и объекты.

В подключаемой части ADO.NET имеются следующие основные классы:

  • Connection. Этот класс, позволяющий устанавливать подключение к источнику данных. ( OleDbConnection, SqlConnection, OracleConnection)
  • Transaction. Объект транзакций (OleDbTransaction, SqlTransaction, OracleTransaction. В ADO.NET имеется пространство имен System.Transaction)
  • DataAdapter. Это своеобразный шлюз между автономными и подключенными аспектами ADO.NET. Он устанавливает подключение, и если подключение уже установлено, содержит достаточно информации, чтобы воспринимать данные автономных объектов и взаимодействовать с базой данных. (DataAdapter — SqlDataAdapter, OracleDataAdapter)
  • Command. Это класс представляющий исполняемую команду в базовом источнике данных.
  • Parameter. Объект параметр команды.
  • DataReader. Это эквивалент конвейерного курсора с возможностью только чтения данных в прямом направлении.

Поведение объектов подключения

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

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

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

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

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

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


Вторым наиболее ресурсоемким объектом в ADO.NET являются транзакции, отвечающие за корректность изменений в БД.

Транзакции

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

Обычно транзакции следуют определенным правилам, Известным как свойства ACID: неделимой (Atomic), согласованной (Consistent), изолированной (Isolated) и долговечной (Durable).

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

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

В ADO.NET класс подключений используется просто для начала транзакции.

Все управляемы NET поставщики, доступные в NET Framework OleDb, SqlClient, OracleClient, ODBC имеют свои собственные реализации класса транзакций.

Все эти классы реализуют интерфейс IDbTransaction из пространства имен System.Data.

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

Подключение к БД необходимо производить перед вызовом метода BeginTransaction класса Connection. Так как в данном случае ресурс физического подключения используется меньше, что уменьшает нагрузку на СУБД.

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

Для гибкого управления поведением транзакций используется уровни изоляции.

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

Например, если в SQL Server две транзакции запущенны, не зависимо одна от другой, то по умолчанию записи, вставленные одной транзакцией, не видны в другой, пока первая транзакция не будет зафиксирована.

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

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

  1. Неверного извлечения данных, называемое «грязным чтением»
  2. «Невоспроизводимое чтение» — это состояние, когда транзакция, ранее работающая с данными, пытается вновь осуществить с этими данными взаимодействие, но между этими взаимодействиями другая транзакция произвела изменения данных, при этом первая транзакция работает уже с низменными данными.
  3. «Фантомные строки» — пусть транзакция А работает с набором из 100 строк выбранные по определенные критерием, а транзакция. Б изменяет данные, в результате чего при повторной выборке транзакцией А она имеет уже другой набор строк.

В ADO.NET уровни транзакций описаны в перечислении IsolationLevel:

  • Chaos. Ожидающие записи изменения транзакций более высоких уровней изоляций не могут быть перезаписаны. Это параметр не поддерживается в SQL Server и Oracle
  • ReadUncommited. Разрешается «грязное чтение». Пример использования: мониторинг системы администратором.
  • ReadCommited. Пока транзакция читает данные, удерживается «разделяемые блокировки. Это позволяет избежать «грязного чтения», но данные могут быть изменены до завершения транзакции. В результате может возникнуть «невоспроизводимое чтение». Или может возникнуть «фантомные строки». Этот уровень изоляции поддерживается в Oracle и SLQ Server.
  • RepeatableRead. В этом случае разделяемые блокировки устанавливаются на все данные, используемые в предикате (критерии) запроса. Это предотвращает модификацию данных другими транзакциями и невоспроизводимое чтение. Однако возможны и фантомные строки. Этот уровень изоляции не поддерживается в Oracle.
  • Snapshot. Этот уровень изоляции уменьшает вероятность установки блокировки строк, сохраняя копию данных, которые одно приложение может читать, в то время как другое модифицирует эти же данные.
  • Serializable. В этом случае данные блокируются, что предотвращает обновление или вставку строк в DataSet другими пользователя до тех пор, пока транзакция не завершится. Эту блокировку можно установить на строку, страницу или таблицу. Данный уровень изоляции поддерживается в Oracle

При откате транзакции происходит аннулирование эффекта каждой операции транзакции. В некоторых случаях не требуется отменять все операции — значит, нужен механизм отката только части транзакцию. Это можно реализовать с помощью «точек сохранения».

Точки отката — это маркеры, реализующие роль закладок. Во время выполнения транзакции, можно поместить какую-либо точку, и затем выполнить откат к этой точки вместо полного отката всей транзакции. Для этих целей предусмотрен метод Save в объекте транзакции. Но надо отметит, что данный метод доступен лишь для подключений к SQL SERVER. Поставщик Oracle не поддерживает точки сохранения, но их всегда можно реализовать через прямые запросы или используя хранимые процедуры.

Но есть несколько моментов делающее точки сохранения не очень удобными. Одна из них заключается в том, что необходимо вызывать методы Commit Rollback при откате транзакции к одной из точек сохранения. Еще на что стоит обратить внимание, что после отката транзакции к определенной точке, все точки отказа находящиеся за текущей теряются. И если возникнет в них потребность, их придется установить заново.

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

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

В распределенных транзакциях могут быть блоки, называtvst диспетчерами ресурсов (resource manager — RM). Но кроме этих диспетчеров необходимо приложение, прислушивающиеся к ним и координирующие их действия. Оно называется координатором распределенных транзакций (Distributed Transaction Coordinator — DTC) или диспетчером транзакций.

Координатор транзакций, которых представлен с Windows, называется координатором распределенных транзакций Microsoft (MSDTC) и представляет собой службу Windows, которая выполняет координацию транзакций для распределенных транзакций.

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

  • Приложение начинает транзакцию, запрашивая ее у MSDTC. Это приложение обычно называется инициатором.
  • Затем приложение предлагает RM выполнить свою работу в составе этой транзакции, и диспетчеры ресурсов регистрируются в диспетчере транзакций в качестве части этой же транзакции. Обычно это называется включением и занесением в транзакцию.
  • Если все нормально, то приложение фиксирует транзакцию.
  • Если что-то не так, каждый шаг может выполнять откат.
  • в любом случае, координатор транзакций координирует работу всех RM, чтобы обеспечить, что-либо все они завершились успешно и выполнили нужную работу, либо все они отменили результаты своей работы.

При работе с распределенными транзакциями различные RM должны реализовывать надежный протокол фиксации: наиболее распространенная реализация такого протокола называется двух фазной фиксацией (two-phase commit).

Технология Клиент-Сервер 2001’2
Home Поиск Издания Контакты k-press.ru

ADO.NET (ActiveX Data Object.NET) – набор классов, используемый для доступа к источникам данных в платформе .NET. Название ADO.NET означает, что данный набор классов – это логическое развитие предыдущей объектной модели доступа к данным – ADO. Но ADO.NET не просто следующая версия ADO. ADO.NET представляет собой новую объектную модель, которая использует стандарт XML для передачи данных. ADO.Net развивает идею использования отсоединенных массивов данных, переводя ее из разряда дополнительных возможностей в разряд реально используемых, более того – основных способов работы. По сравнению с ADO, ADO.NET обещает более легкое программирование, лучшую производительность и масштабирование, меньшую зависимость от особенностей источников данных и большую способность взаимодействовать с другими платформами.

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

Объектная модель ADO.NET

Примерную объектную модель ADO.NET можно представить следующей диаграммой:

В предыдущих версиях ADO основным объектом для работы с данными был объект Recordset, хранящий результат выполнения запроса – набор строк и колонок. Хотя ADO и позволял создавать отсоединенные наборы данных, это не было его основной задачей. Он был предназначен для работы с данными, использующей постоянное соединение с источником данных.

В ADO.NET все изменилось. Теперь ключевой объект, который хранит данные в ADO.NET – DataSet. Это экземпляр CLR-класса System.Data.DataSet, представляющий моментальный снимок части базы данных, размещенный в памяти.

В ADO объект Recordset использует другие объекты ADO для соединения с источником данных. DataSet – независимый от источника данных объект, который не имеет собственных средств для работы с источниками данных. Связующую роль между DataSet и источником данных в ADO.NET выполняют управляемые (managed) провайдеры. Каждый управляемый провайдер представляет набор объектов, с помощью которых можно подключиться к источнику данных, считать данные и заполнить ими DataSet. Это позволяет DataSet не знать ничего про соединения с источниками данных.

Преимущества ADO.NET

ADO.NET создан для использования в управляемых (managed) проектах. Старый ADO основан на технологии COM и при использовании из управляемых приложений требует дополнительных затрат на выполнение прокси-кода. К тому же ADO имеет меньшие возможности при работе с отключенными наборами данных и XML. Например, в ADO было непросто сохранить изменения, произведенные в отключенном курсоре. Вот некоторые преимущества ADO.NET в сравнении с ADO:

Масштабируемость

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

Независимость от источника данных

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

Способность к взаимодействию

Так как ADO.NET использует XML как стандартный формат передачи данных, программа, которой необходимо получить данные из компонента ADO.NET, не обязана сама быть компонентом ADO.NET. В общем случае она вообще может не быть Windows-программой. Единственное требование – эта программа должна понимать XML. И это позволяет ADO.NET-компонентам при использовании других компонентов и сервисов, входящих в VS.Net, легко взаимодействовать с любой программой на любой платформе.

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

Типизированные поля

В ADO из-за того, что нужно было обеспечить работу и в скриптовых языках, работа со значениями ячейки шла через тип Variant. И это вызывало некоторое количество проблем – компилятор не имел возможности выполнения проверки на совместимость типов, переменная типа Variant занимала лишнюю память и медленнее обрабатывалась. В последних версиях ADO был добавлен интерфейс IADORecordBinding, позволявший решить эту проблему, но доступен он был только для C++-разработчиков. ADO.NET снимает это ограничение. Теперь данные колонки можно без конвертаций считать в переменную необходимого типа. Стало возможным также создавать классы, производные от DataSet. Такие классы реализуют свойства, сходные с колонками DataSet-а и позволяют осуществлять строго типизированный доступ к полям DataSet-а. При этом можно пользоваться такими функциями среды, как CompleteWord. Генерацию строго типизированных DataSet-ов можно возложить на IDE.

Брандмауэры

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

Название свойства

Описание свойства

Тип элемента коллекции

Описание свойства

Возвращает коллекцию строк таблицы

DataRow

Содержит все значения одной строки таблицы

Columns

Возвращает коллекцию колонок таблицы

DataColumn


Содержит информацию о столбце таблицы (имя, тип данных, и т.д.)

Constraints

Возвращает коллекцию описаний ограничений таблицы

Constraint

Содержит информацию об ограничении таблицы

ParentRelations

Возвращает коллекцию связей таблицы

DataRelation

Содержит информацию о связи с другой таблицей

ChildRelations

Объекты для работы с данными

DataSet

DataSet хранит в себе набор таблиц (считанных полностью или частично из БД) с дополнительной информацией об их структуре и отношениях между ними. Такой подход позволяет более компактно представлять выбранные из источника данные. DataSet предоставляет объектную модель, которая позволяет получить доступ к его внутренним таблицам, их строкам, ячейкам и отношениям между таблицами. С помощью объектов ADO.Net, относящихся к провайдеру, можно выполнять запросы к БД и заполнять таблицы объекта DataSet.

Основную нагрузку по хранению и обработке данных в DataSet несет на себе коллекция DataTableCollection Tables, содержащая объекты типа DataTable. В объекте DataTable хранятся данные одной таблицы DataSet-а. DataTable в свою очередь содержит несколько коллекций, описывающих хранимую таблицу. В таблице 1 приведено описание свойств, позволяющих получить доступ к этим коллекциям.

Управляемые провайдеры (managed providers)

Раньше, до появления ADO.NET, ADO был надстройкой над OLE DB. Это означало, что при подключении к источнику данных с помощью ADO на самом деле вся работа выполнялась OLE DB. COM-природа OLE DB приводит к тому, что управляемое приложение вынуждено использовать прокси для взаимодействия с провайдером. По всей видимости, чтобы избежать неоправданных накладных расходов, разработчики Microsoft решили кроме поддержки OLE DB-провайдеров ввести прямые, так называемые (managed) управляемые провайдеры. Управляемый провайдер может использовать более низкоуровневые API, нежели OLE DB, специфичные для конкретного источника данных. Это позволяет производить необходимую обработку данных сразу в управляемом коде, не тратя времени на прокси-вызовы.

Управляемый провайдер данных – это набор объектов ADO.NET, разработанных для соединения с определенным источником данных. Все провайдеры обеспечивают одинаковый набор базовых методов и свойств, скрывая в своей реализации всю работу с API доступа к источнику данных. Необходимо только знать, какой управляемый провайдер должен использоваться в конкретном случае.

Илон Маск рекомендует:  Что такое код gzputs

Текущая доступная версия .NET Framework (beta 2) представляет два управляемых провайдера:

  • Управляемый провайдер SQL для доступа к данным, расположенным на серверах баз данных Microsoft SQL Server 7 и выше (SqlConnection)
  • Управляемый провайдер для доступа к данным через OLE DB (OleDbConnection). Его можно использовать для доступа к базам данных Access и Oracle, Active Directory, каталогам LDAP и другим источникам, поддерживающим OLE DB или ODBC.

При использовании SQL провайдера используются объекты SqlConnection, SqlCommand, SqlDataReader и SqlDataAdapter (эти объекты находятся в пространстве имен System.Data.SqlClient). Если же вы работаете с провайдером для OLE DB, то соответственно необходимо использовать объекты OleDbConnection, OleDbCommand, OleDbDataReader и OleDbDataAdapter (пространство имен System.Data.OleDb).

Почему Microsoft вообще не отказалась от использования OLE DB? Все очень просто – провайдеры тяжелы в реализации, а для OLE DB и ODBC создано много провайдеров и драйверов.

DataReader

Использование DataSet оправдано, если необходимо передать данные в формате XML на другой компьютер, например, для их отображения и редактирования или дополнительной обработки. Использование DataSet также оправдано, если необходимо вывести данные в гриде или подключить к полям формы. Если же необходимые данные используются непосредственно там, где они запрашивались, и нужно всего лишь перебрать их по очереди, лучше воспользоваться объектом типа DataReader (SqlDataReader или OleDbDataReader).

Объект DataReader очень похож на forward-only read-only Recordset в ADO. Данный объект считывает одну запись из источника данных (с помощью метода Read()) за одно обращение и позволяет получить доступ к содержимому записи. Его имеет смысл применять в случае, если надо просто прочитать данные из источника данных и выполнить с ними какие-либо действия (например, вывести на ASP-страницу).

Примеры работы с ADO.NET

Теперь посмотрим на применение ADO.NET на практике. Мы рассмотрим примеры нескольких способов чтения данных из базы данных и их изменения. В качестве базы данных будет использоваться Pubs – демонстрационная база данных, входящая в состав поставки MS SQL. В примерах будут использоваться управляемый провайдер SQL. Полученный результат будет отображаться с помощью элемента управления asp:DataGrid. Новая версия ASP – ASP.Net позволяет работать с элементами Web-страницы как с элементами пользовательского интерфейса, размещенными на форме VB. asp:DataGrid – это один из новых компонентов, позволяющих упростить разработку Web-страниц.

Чтение данных в DataSet

Итак, первое ADO.NET приложение. В первом примере мы выведем на страницу содержимое таблицы Authors. Код страницы, выполняющий данное действие, приведен ниже:

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

Обратите внимание на функцию Page_Load, в которой и выполняется весь наш код. В ней создается экземпляр объекта SqlConnection, представляющий собой подключение к источнику данных. В конструкторе этого объекта передается строка подключения к нужной базе данных. Затем создается экземпляр объекта SqlDataAdapter, играющий роль связующего звена между провайдером источника данных и объектом DataSet. В конструкторе этого объекта передаются SQL-запрос к базе данных и ранее созданный объект SqlConnection. Затем создается экземпляр DataSet, и с помощью метода Fill объекта SqldataAdapter заполняется необходимыми данными. Полученный DataSet связывается с элементом управления DataGrid. На этом создание простейшей страницы для вывода данных с помощью объекта DataSet закончено. Первая ADO.NET-страница готова. (Работа с DataGrid будет рассмотрена далее в этой статье в разделе «Связывание данных с элементами web-формы»).

Чтение данных. DataReader.

Теперь рассмотрим вопрос о доступе к данным с помощью объекта DataReader. Как уже говорилось ранее, DataReader создает forward-only read-only курсор, хорошо знакомый всем программистам, когда-либо использовавшим ADO. DataReader читает одну запись из источника данных за раз.

В примере будет показан способ чтения данных из таблицы jobs из базы Pubs и вывода прочитанных данных в ListBox. Код страницы, выполняющей это действие, приведен ниже:

Примерный результат выполнения этой страницы вы можете увидеть здесь:

Рисунок 3. Вывод результатов запроса с помощью DataReader.

Весь код опять-таки выполняется в методе Page_Load. Как и в предыдущем примере, создается экземпляр объекта SqlConnection со строкой подключения к базе. Затем создается экземпляр объекта SqlCommand (а не SqlDataSetCommand, как в прошлом примере). Открывается соединение с базой данных (myConn.Open()) и вызывается метод ExecuteReader объекта SqlCommand, который возвращает экземпляр объекта SqlDataReader. После этого в цикле осуществляется проход по полученному myReader, и в ListBox добавляются значения, полученные из базы данных. В конце соединение с базой данных закрывается.

Код для отображения текста/значения выбранного элемента ListBox добавлен только для проверки.

Этот код приведен только для примера применения объекта DataReader. Намного эффективнее было бы, конечно же, заполнить DataSet и связать его с ListBox. Как уже упоминалось ранее, вопрос связывания данных с элементами управления на web-странице мы рассмотрим позже.

Чтение данных. Получение результатов выполнения хранимых процедур

В предыдущих примерах было описано получение результатов запросов select и их вывод на web-страницу. Но это не единственный способ получения каких-либо результатов от источника данных. Сейчас мы обратимся к работе с хранимыми процедурами – вызову хранимых процедур, передаче и возврату параметров в хранимых процедурах, а также возврату наборов записей из хранимых процедур с помощью ADO.NET.

Для начала рассмотрим вызов хранимой процедуры с передачей в нее параметров, и получение значения, возвращаемого хранимой процедурой с помощью оператора return. Для этого в базу pubs необходимо добавить следующую хранимую процедуру:

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

Теперь напишем ASP.NET-страницу, которая позволит нам вызвать эту процедуру. Ее код приведен ниже:

Результат выполнения хранимой процедуры при введенном в поле «Штат» значении “CA” (без кавычек) вы можете увидеть здесь (Рисунок 4):

Весь полезный код выполняется в методе SubmitBtn_Click. В нем вызывается хранимая процедура, ей передаются параметры, и возвращаемое значение выводится на страницу. Итак, как обычно создается экземпляр объекта SqlConnection для подключения к базе данных. Затем создается экземпляр объекта SqlCommand, и ему передается имя вызываемой хранимой процедуры. Для передачи параметров используется свойство Parameters объекта SqlCommand, представляющее собой коллекцию объектов SqlParameter. Эта коллекция предназначена для определения всех параметров хранимой процедуры (входных, выходных и возвращаемого значения). С помощью метода Add этой коллекции в хранимую процедуру добавляются 2 параметра – @state (входной параметр) и RETURN_VALUE (параметр, через который будет возвращаться результат выполнения хранимой процедуры). Для параметра @state устанавливается значение, введенное в поле ввода, а для RETURN_VALUE устанавливается Direction в ParameterDirection.ReturnValue. Также необходимо установить CommandType у объекта SqlCommand в CommandType.StoredProcedure. Затем для реального вызова хранимой процедуры открывается соединение с источником данных, исполняется запрос (с помощью метода ExecuteNonQuery()), вернувшееся значение записывается в Label и соединение закрывается. Создание страницы для вызова хранимой процедуры завершено.

Чтение данных. Получение набора записей из хранимой процедуры

Последним примером, связанным с получением данных из источника, будет вызов хранимой процедуры, возвращающей набор данных. Для этого будет вызываться хранимая процедура reptg4 – немного измененный вариант хранимой процедуры reptg3 из базы pubs. Для отображения данных будет использоваться уже знакомая связка объектов SqlDataAdapter-DataSet.

Страница из примера будет искать книги с ценой, лежащей в пределах MinPrice – MaxPrice и входящих в категорию Type или в категорию, название которой содержит в себе слово “cook».

Вначале представлен текст хранимой процедуры, которую необходимо добавить в базу pubs:

Рассмотрим нашу страницу. Во-первых, мы должны были обеспечить возможность передачи параметров в хранимую процедуру. Для этой цели мы разместили на странице текстовые поля tbMinPrice и tbMaxPrice и выпадающий список ccType, предназначенные соответственно для ввода значений минимальной и максимальной цены, и выбора типа книги. Мы также поместили элемент DataGrid для вывода полученных результатов.

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

Объект SqlDataAdapter имеет свойства SelectCommand, InsertCommand, UpdateCommand и DeleteCommand, имеющие тип SqlCommand. Пример работы с объектом SqlCommand уже был рассмотрен ранее. Более подробно работу с этими свойствами мы рассмотрим немного позднее, а сейчас только посмотрим, каким образом мы можем вызвать хранимую процедуру и передать ей параметры.

Итак, после создания объекта SqlDataAdapter необходимо изменить тип SelectCommand на CommandType.StoredProcedure и потом, как и в предыдущем примере, заполнить коллекцию Parameters этого объекта для передачи параметров в хранимую процедуру. После передачи всех параметров необходимо (как и в первом примере с использованием DataSet) вызвать метод Fill для заполнения DataSet результатами выполнения хранимой процедуры. Связывание DataSet с DataGrid выводит полученный результат на страницу.

Изменение данных. Простые примеры

Мы рассмотрели вопрос вызова SELECT запросов с помощью объекта SqlCommand. Очень часто вы будете применять этот объект и для изменения данных – для выполнения одиночных SQL команд INSERT, UPDATE или DELETE, или вызова хранимых процедур, производящих изменения в базе данных. Далее будет кратко рассмотрен пример страницы, производящей такие изменения в таблице jobs базы pubs. Вначале в таблицу будет добавлена новая запись, потом эта запись будет изменена и затем удалена. Добавление будет сделано с помощью конструируемого запроса INSERT, обновление — с помощью параметризированного запроса, а удалена запись будет вызовом хранимой процедуры без параметров. После каждой операции в DataGrid на страницу будут выводиться текущие данные таблицы jobs.

Код процедуры удаления:

Весь код, выполняющий обработку данных, находится в методе Page_OnLoad. При первом запуске данной страницы выполняется вызов хранимой процедуры delJobs, которая удаляет все ранее введенные нами jobs. Затем, в зависимости от значения ViewState[«currStep”] (переменной, в которой сохраняется текущий шаг страницы – добавление, изменение или удаление) выполняются соответствующие действия. Рассмотрим их более подробно.

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

Обновление данных. Для обновления используется команда UPDATE с параметрами. Затем, как и при работе с хранимыми процедурами, требующими параметров, заполняется коллекция Parameters объекта SqlCommand и выполняется запрос.

Удаление данных. Для удаления записей просто вызывается приведенная выше хранимая процедура.

Изменение данных. Работа связки DataSet + DataAdapter.

.NET Framework предоставляет очень мощную возможность редактирования данных с помощью объектов DataSet и SqlDataAdapter (AdoDataAdapter). После заполнения DataSet с помощью DataAdapter вы можете без проблем редактировать данные в DataSet. А когда придет время сохранить изменения в данных, это легко можно будет сделать с помощью метода Update объекта DataAdapter.

Рассмотрим работу данного алгоритма на примере. Заполним DataSet данными из таблицы jobs. Затем изменим данные в одной строке и добавим еще одну строку, после чего запишем данные обратно в базу и заново их прочтем для того, чтобы вывести на страницу результат и проконтролировать выполнение операций изменения и добавления.


Первоначальный вид страницы:

Страница после нажатия кнопки (изменена строка с job_ >

Возможность использования связки DataSet + DataAdapter состоит в том, что объект SqlDataAdapter кроме свойства SelectCommand (команда, с помощью которой происходит выборка данных из источника данных) использует также команды для изменения данных (DeleteCommand, InsertCommand и UpdateCommand). Вся сложность при этом заключается в правильном присвоении значений (команд SQL) этим свойствам для корректного обновления данных в базе данных. Большую помощь в этом оказывает объект SqlCommandBuilder, предназначенный для автоматической генерации команд, использующихся для обновления данных. Ну а дальше все просто. Создается объект SqlDataAdapter, заполняется DataSet, и производятся манипуляции с данными. Затем в нужный момент с помощью SqlCommandBuilder генерируются команды для обновления данных, и вызывается метод SqlDataAdapter.Update для записи изменений данных в базу. ..

Заключение

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

** Полностью статью можно найти в печатной версии журнала

Copyright © 1994-2020 ООО «К-Пресс»

Работа с подключенным уровнем ADO .NET в C#

FAQ для раздела “ADO.NET и базы данных”

Тема: ”Работа с подключенным уровнем ADO .NET в C#”

1) Теоретическая часть
1.1 Поставщики данных .NET Framework (ADO.NET)
1.2 Основные объекты поставщиков данных .NET Framework:
1.3 Пару слов об интерфейсах IDataReader и IDbCommand
1.4 Подробнее о поставщике данных для SQL Server

2) Практическая часть

2.1 Как создать БД?
2.2 Как создать таблицу?
2.3 Как вывести все записи из таблицы?
2.4 Как добавить запись в таблицу?
2.5 Как удалить запись из таблицы?
2.6 Как изменить запись в таблице?
2.7 Как удалить таблицу?
2.8 Собирая все вместе

1. Теоретическая часть

Здравствуйте! В этом FAQ я расскажу, некоторые основные аспекты работы с подключенным уровнем ADO .NET в C#( на примере подключения к БД MS SQL Server ) и начнем мы с рассмотрения поставщиков данных:

1.1 Поставщики данных .NET Framework (ADO.NET)

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

Cписок поставщиков данных .NET Framework:

• .NET Framework Поставщик данных для SQL Server
Предоставляет доступ к данным для Microsoft SQL Server 7.0 или более поздних версий.Использует пространство имен System.Data.SqlClient.

• .NET Framework Поставщик данных для OLE DB
Для источников данных OLE DB.Использует пространство имен System.Data.OleDb.

• .NET Framework Поставщик данных для ODBC
Для источников данных ODBC.Использует пространство имен System.Data.Odbc.

• .NET Framework Поставщик данных для Oracle
Для источников данных Oracle.Источник данных .NET Framework для Oracle поддерживает клиентское программное обеспечение версии 8.1.7 и старше и использует пространство имен System.Data.OracleClient.

• Поставщик EntityClient
Предоставляет доступ к данным для приложений модели EDM (Entity Data Model).Использует пространство имен System.Data.EntityClient.

1.2 Основные объекты поставщиков данных .NET Framework:

Connection
Устанавливает соединение с конкретным источником данных.Базовым классом для всех объектов Connection является DbConnection.

Command
Выполняет команду в источнике данных.Обеспечивает доступность Parameters и может выполнять команды в области Transaction из Connection.Базовым классом для всех объектов Command является DbCommand.

DataReader
Считывает из источника данных однопроходный поток данных только для чтения.Базовым классом для всех объектов DataReader является DbDataReader.

DataAdapter
Заполняет DataSet и выполняет обновления в источнике данных.Базовым классом для всех объектов DataAdapter является DbDataAdapter.

1.3 Пару слов об интерфейсах IDataReader и IDbCommand

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

Пространство имен: System.Data

Интерфейсы IDataReader и IDataRecord позволяют классу-наследнику реализовать класс DataReader, позволяющий читать один или несколько потоков наборов результатов только в направлении вперед. Приложение создает не непосредственно экземпляр интерфейса IDataReader, а экземпляр класса, являющегося наследником IDataReader.
Классы, являющиеся наследниками IDataReader, должны реализовывать наследуемые члены. Обычно они также определяют дополнительные члены для добавления функциональных возможностей, зависящих от поставщика данных.

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

Примечания для реализующих объектов:

Для достижения единообразия среди поставщиков данных .NET Framework наследующие классы следует именовать в форме Prv «команда», где Prv — постоянный префикс, назначаемый всем классам в пространстве имен определенного поставщика данных .NET Framework. Например, Sql является префиксом класса SqlDataAdapter в пространстве имен System.Data.SqlClient.

Представляет собой оператор SQL, исполняемый при подключении к источнику данных и реализуемый поставщиками данных .NET Framework, которые имеют доступ к реляционным базам данных.

Пространство имен: System.Data

Интерфейс IDbCommand позволяет наследующему классу реализовывать класс Command, являющийся инструкцией SQL, исполняемой в источнике данных.
Приложение создает не непосредственно экземпляр интерфейса IDbCommand, а экземпляр класса, являющегося наследником IDbCommand.
Классы, наследующие IDbCommand, должны реализовывать все наследуемые элементы. Обычно они также определяют дополнительные элементы для добавления функциональных возможностей, зависящих от поставщика. Например, интерфейс IDbCommand определяет метод ExecuteNonQuery. В свою очередь, класс SqlCommand наследует этот метод, а также определяет метод ExecuteXmlReader.

Примечания для реализующих объектов:

Для достижения единообразия среди поставщиков данных .NET Framework наследующие классы следует называть в форме PrvClassname, где Prv — постоянный префикс, назначаемый всем классам в пространстве имен определенного поставщика данных .NET Framework. Например, Sql является префиксом класса SqlCommand в пространстве имен System.Data.SqlClient.

1.4 Подробнее о поставщике данных для SQL Server

В данном FAQ мы рассмотрим 4 класса — SqlConnection, SqlCommand, SqlDataReader, SqlParameter .

Предоставляет открытое подключение к базе данных SQL Server.Этот класс не может быть унаследован.

Пространство имен: System.Data.SqlClient

public sealed class SqlConnection : DbConnection,
ICloneable

Представляет инструкцию Transact-SQL или хранимую процедуру, выполняемую над базой данных SQL Server.Этот класс не может быть унаследован.

Пространство имен: System.Data.SqlClient

public sealed class SqlCommand : DbCommand,
ICloneable

Предоставляет возможность чтения потока строк только в прямом направлении из базы данных SQL Server.Данный класс не может наследоваться.

Пространство имен: System.Data.SqlClient

public class SqlDataReader : DbDataReader,
IDataReader, IDisposable, IDataRecord

Предоставляет параметр для объекта SqlCommand и, при необходимости, его отображение на DataSet.Этот класс не может быть унаследован.

Пространство имен: System.Data.SqlClient

public sealed class SqlParameter : DbParameter,
IDbDataParameter, IDataParameter, ICloneable

Но все это были общие понятия, а теперь перейдём к практике.

Сравнение скорости доступа к данным (ADO.NET, ADO, ascDB)

Автор: Станислав Михаилов
optim.su
Источник: RSDN Magazine #3

Опубликовано: 10.05.2003
Исправлено: 05.01.2007
Версия текста: 1.0.1

Вступление

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

Также показалось любопытным, есть ли отличия в работе с ADO.NET через COM+ и NetRemoting? Стоит ли по-прежнему использовать COM+ в качестве сервера приложений? Возможно, NetRemoting работает значительно быстрее, чем COM+, или при использовании COM+ с .NET возникают какие-то непреодолимые проблемы?

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

Ответам на эти и смежные с ними вопросы посвящена данная статья.

Описание тестов

Тестировались три средства доступа к данным: ADO.NET (C#), ADO (VB6) и ascDB (VB6). Использовался MS SQL Server 2000.

В качестве тестовых таблиц использовались копии таблицы Orders из базы Northwind стандартной поставки MS SQL Server 2000. Таблицы содержат 14 колонок со следующими типами данных: int (3 колонки), money (одна колонка), datetime (3 колонки), строки с длиной от 5 до 60 символов (7 колонок). Таблицы создавались в отдельной базе данных и не связаны с другими таблицами или между собой.


Для каждого случая выполнялись 5 тестов. Каждый тест выполнялся в «in-process режиме», в «локальном режиме через COM+» и в «удаленном режиме через COM+». Отдельно для ADO.NET тесты запускались дополнительно в «локальном режиме через NET Remoting» и «удаленном режиме через NET Remoting».

В качестве тестовой машины в «in-process режиме» и «локальном режиме через COM+», а также в качестве сервера в удаленных режимах, использовался компьютер со следующими параметрами:

  • ОС Microsoft Windows 2000 Server Service Pack 2
  • Athlon 1400 MHz
  • RAM 256 Мб
  • Page File 768 Мб

В качестве клиентской машины в удаленных режимах использовался компьютер со следующими параметрами:

  • ОС: Microsoft Windows 2000 Server Service Pack 2
  • P-III 800 Mhz
  • RAM 384 Мб
  • Page File 1 Гб

В удаленных режимах использовалась локальная сеть Ethernet 10BaseT (10 Мегабит/с).

Общие сведения по режимам тестирования


«In-process режим»

В «in-process режиме» (без использования COM+) весь исполняемый код находился в клиентском exe-приложении, то есть приложение напрямую работало с базой данных, минуя промежуточное копирование данных и передачу их между процессами.

Этот режим является типичным для работы web-приложений.

«Локальный режим через COM+»

Во всех остальных режимах работа велась через отдельный промежуточный (middleware) COM-объект, создаваемый в другом процессе («локальный режим через COM+») или на удаленном компьютере («удаленный режим через COM+» и «удаленный режим через NET Remoting»). В этом объекте происходило получение result-set’a, данные из которого затем возвращались клиентскому приложению. Для передачи данных между процессами использовались объекты ascCachedCursor (ascDB), Recordset (ADO) и DataSet (ADO.NET) (они возвращались клиентскому приложению методами промежуточного объекта).

«Локальный режим через NET Remoting»

Аналог «локального режима через COM+», за исключением того, что вместо COM+ использовалась технология NET Remoting. В этом режиме тестировался только ADO.NET.

«Удаленный режим через COM+»

Аналог «локального режима через COM+», за исключением того, что на клиентской машине был установлен COM+ proxy, и передача данных осуществлялась не между процессами на одной машине, а по сети.

«Удаленный режим через NET Remoting»

Аналог «локального режима через NET Remoting» за исключением того, что передача данных осуществлялась не между процессами на одной машине, а по сети. Этот режим тестировался только для ADO.NET.

Общие сведения по тестам

Выполнялись следующие тесты:

  1. «Forward» – получение аналога forward-only курсора на 1 млн. записей с прокруткой его на первые сто записей.
  2. «LargeKeySet» – получение аналога static-курсора на 100 тыс. записей и прокрутка его на несколько значительно удаленных друг от друга позиций (прыжок методом, аналогичным FetchRandom, на позицию 10, 30, 50, 75 и 100 процентов от общего количества записей, и возврат на первую запись).
  3. «ChangeData» – получение аналога keyset-курсора на 10 тыс. записей и выполнение с ним действий, имитирующих реальную работу (перебор, добавление, изменение, удаление записей, сохранение и переоткрытие курсора).
  4. «Top 10» – получение 10 первых записей с их перебором (fetch).
  5. «Top 100» аналогичен тесту «Top 10», за исключением того, что выбирались первые 100, а не 10 записей.

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


Тест «Forward»

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

Такой метод зачастую применялся раньше в случаях, когда результирующая выборка может потенциально иметь большой объем, но пользователю требуется постраничная прокрутка. При этом все время жизни клиентской сессии должна сохраняться связь с БД. Иногда применялся прием, при котором связь с БД разрывалась, но при запросе следующей страницы производилась прокрутка до нужной страницы и считывание нужного блока. Особенности forward-only-курсора позволяют быстро получить первые записи выборки (так как SQL Server, по сути, использует алгоритм выборки и хранит позицию, а физическая выборка осуществляется в момент пролистывания курсора на клиенте). Эти особенности позволяют очень быстро осуществлять пропускание ненужных записей. Однако оказалось, что сейчас не все средства доступа к БД поддерживают этот режим работы. Так, оказалось, что ADO.NET предназначено исключительно для отключенного режима работы и, как следствие, показывает плохие результаты, если производится неполное считывание данных, возвращаемых запросом. Но об этом немного позже.

Во всех режимах тестирования, кроме in-process, на серверной стороне выполнялся запрос «select * from Orders1000000» (в таблице 1 млн. записей). Затем первый блок данных (100 строк) передавался на клиентскую сторону, где по ним выполнялся перебор (fetch) с копированием данных в переменные класса (переменные класса использовались во избежание потенциальной оптимизации компилятором).

В in-process режиме запрос выполнялся на клиентской стороне без отключения от БД. В связи с этим в ADO.NET в этом режиме использовался SqlDataReader, а не SqlDataAdapter.

Затем выполнялось переоткрытие курсора. Использовались forwardonly-курсоры или их аналоги (SqlDataReader в ADO.NET). В тестах ADO.NET для всех режимов, кроме in-process, forwardonly-курсор имитировался поблочным копированием данных в промежуточные объекты DataSet, которые затем пересылались в клиентское приложение (подробности см. ниже, в описании этого теста для ADO.NET). Выполнялось 10 повторов.

Тест «Forward», ADO.NET

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

Как видно из графика на рисунке 1, время выполнения теста в первый раз примерно втрое превосходит «устоявшееся» значение (получаемое начиная с 6-й итерации). Время выполнения итераций с 1-й по 6-ю постепенно уменьшается и не может быть использовано для анализа «средней скорости» выполнения теста, поскольку не является «типичным». Как будет показано ниже, ADO.NET пытается кэшировать содержимое всего resultset’a. Это приводит не только к тому, что все данные копируются на клиента, но и к тому, что SQL-сервер вынужден обращаться ко всем данным большой таблицы. Особенности SQL-сервера таковы, что он выходит на оптимальный режим работы (производит полное кэширование таблицы и оптимизирует план выборки) только к какой-то N-й итерации. Увеличение объема оперативной памяти должно уменьшить количество итераций до выхода на оптимальный режим.

Однако это не имеет существенного значения для серверных приложений. Уже после первого десятка запусков ситуация нормализуется и ADO.NET выйден на оптимальный (по скорости) режим работы.

В тестах других продуктов (ADO, ascDB) все запуски, кроме первого, как правило, имели разброс значений не более 10%.

«In-process режим»

В качестве аналога forward-only курсора в ADO.NET был использован SqlDataReader. Выполнялось пересоздание объекта SqlDataReader и считывание первых 100 записей из него методом Read. Основной код теста выглядит так:

В процессе отладки оказалось, что даже если вызывать только метод SqlDataReader.Read (без вызова методов SqlDataReader.GetXXX), разницы во времени практически нет – очевидно, что при вызове метода Read объект SqlDataReader честно считывает из курсора БД все данные, относящиеся к новой строке. Однако: «порядок есть порядок» (с) народная немецкая поговорка.

«Локальный режим через COM+»

В результате переноса кода работы с БД в middleware-объект, объект SqlDataReader оказался «отрезанным» от клиента. Поскольку кэширование миллиона записей для передачи их в клиентское приложение не выглядит разумным, было решено сделать «довесочек» к ADO.Net в виде ручного пролистывания курсора.

На первый взгляд задача, выполняемая в этом тесте, может показаться «высосанной из пальца», однако это не так. Поблочное чтение информации используется, например, при пролистывании большой таблицы (скажем, по 100 записей за раз).

Казалось бы, для реализации поблочного чтения данных лучше всего подходит SqlDataAdapter. Все, что надо сделать для заполнения блока с использованием объекта SqlDataAdapter, так это вызвать его метод Fill, в параметры которого передать начальный номер записи и количество записей в блоке.

Это и было сделано. Чтение данных из объекта SqlDataAdapter выполнялось поблочно (по 100 записей), эти блоки в виде объектов DataSet отправлялись клиенту. На клиенте блоки принимались и копировались в конец основного объекта DataSet. Таким образом имитировался forwardonly-курсор на ADO.NET (см. код примера ниже).

И действительно, пока тестировалось получение только первого блока (первые 100 записей), время выполнения теста выглядело терпимо и почти не отличалось от «in-process режима», где использовался SqlDataReader (примерно 5.5 секунд).

Однако увеличение количества блоков до пяти (500 записей) привело в возрастанию затрат времени на их получение почти до полуминуты, а считывание 25-ти блоков заняло, соответственно, 2.5 минуты.

Очевидно, что объект SqlDataAdapter каждый раз для получения нового блока данных внутри себя переоткрывает SqlDataReader и копирует данные из него в DataSet.

Но даже результат, достигнутый с использованием SqlDataReader (5.5 секунды), совершенно неприемлем для выборки первых 100 записей. С чем же это связано, спросите вы. Эксперименты показали, что, вероятнее всего, это происходит из-за слишком большого предварительного кэширования внутри объекта DataReader при обращении к большой таблице. Хотя нами выбирались всего 100 первых записей, было отчетливо заметно, что Reader кэшировал сотни тысяч записей. Такое предположение было сделано на основании двух экспериментов. В первом мы физически ограничили запрос 100 записями (добавив «top 100» в SQL-запрос), а во втором мы попытались пролистать несколько сот тысяч записей. В первом случае запрос начал выполняться молниеносно, а во втором на каждые 100 тыс. записей уходило примерно по 1.2 секунды. Скорее всего, это время затрачивается Reader на считывание данных из кэша. Более подробно результаты работы SqlDataReader представлены в таблице 2. Отсюда можно заключить, что, работая с ADO.NET, а особенно с SQL-провайдером, нужно избегать запросов, потенциально способных вернуть большое количество строк. Для этого можно принудительно ограничивать количество записей непосредственно в запросе оператором «top xxx». Второй вывод – ADO.NET может оказаться идеальным средством для скачивания очень больших объемов данных, т.к. вышеописанное поведение приводит к повышению скорости считывания больших объемов данных. Как видно из той же таблицы, разница между считыванием одной и 800 тыс. записей составила 3 раза, тогда как другие средства доступа к БД дают одну запись практически мгновенно, а считывание всего resultset’a производят медленнее.

Любопытство заставило собрать аналогичный тест с использованием объекта SqlDataReader вместо объекта SqlDataAdapter. К сожалению, чтение из объекта SqlDataReader возможно только по одной записи, поэтому пришлось выполнить некоторое количество промежуточных действий по созданию и заполнению DataSet’а (см. код примера ниже).

Несмотря на промежуточные действия по копированию данных, на больших объемах использование объекта SqlDataReader оказалось предпочтительнее. Результаты сравнения представлены в таблице 1.

Прокрутка на N записей (в скобках количество блоков), одна итерация: SqlDataReader SqlDataAdapter
1 (1 блок) 5.598 5.508
100 (1 блок) 5.899 5.508
500 (5 блоков) 6.88 28.301
2500 (25 блоков) 7.661 142.945
Таблица 1 COM+ Client (100 записей на блок). Имитация forward-only курсора.

Время выполнения операций по чтению первых 100 записей в обоих случаях оказалось почти одинаковым. Отдельным тестом было установлено, что почти не имеет значения, с какой позиции начинать чтение. Почти все время тратится на повторное открытие SqlDataReader (при использовании SqlDataAdapter объект SqlDataReader переоткрывается неявно при каждом вызове метода Fill). Считывание 100 тыс. записей занимает примерно 1.2 секунды. Любопытно, что объект SqlDataReader не имеет метода, аналогичного методу Skip в ADODb.Recordset. Однако, как показали наши эксперименты, вызов в цикле метода SqlDataReader.Read выполняется очень быстро, и его вызов в цикле может служить заменой методу Skip (что, кстати, и делает SqlDataAdapter). Но не надо забывать, что такая высокая скорость пролистывания SqlDataReader связана с тем, что все данные запроса уже кэшированы, и Read реально почти ничего не делает.

Из вышесказанного следует вывод, что для чтения первого небольшого блока данных можно использовать SqlDataAdapter и не мучиться с объектом SqlDataReader. Однако вообще считывание части resultset’а в ADO.NET крайне неэффективно.

Когда количество блоков доходит до трех-пяти (размер блока 100 записей), то работа через SqlDataReader становится предпочтительнее (не забывайте, что мы производим докачку, и при считывании каждого блока SqlDataAdapter переоткрывает SqlDataReader). Из таблицы 1 видно, что время, затрачиваемое объектом SqlDataAdapter на чтение новых блоков данных, возрастает почти прямо пропорционально количеству блоков (1 блок – 5 секунд, 5 блоков – 28 секунд, 25 блоков – 143 секунды). Тогда как объект SqlDataReader справляется с возрастанием количества считываемых блоков без особого напряжения (1 блок — 6 секунд, 25 блоков – 8 секунд).

Единственная серьезная проблема при работе с объектом SqlDataReader заключается в том, что на одном SqlConnection может быть открыт только один SqlDataReader.

В тесте «Forward» для реализации подобия forward-only курсора на ADO.NET были опробованы оба варианта. Тест с объектом SqlDataReader выполнялся быстрее, поэтому здесь приводятся приводятся именно его результаты (см. ниже таблицы с результатами теста «Forward» в режимах тестирования через COM+ и NET Remoting).

Примеры основного кода поблочного чтения для клиента (клиентское приложение) и сервера (middleware-объект, зарегистрированный в COM+-приложении) приведены ниже. Для серверной стороны даны два варианта реализации функции Orders1000000Fetch: через SqlDataReader и через SqlDataAdapter.

Чтобы middleware-объект успешно регистрировался и работал через COM+, его нужно реализовать как COM-объект. Для этого в подразделе Build раздела настроек конфигурации (Configuration Properties) в настройках проекта (Project Properties) значение настройки “Register for COM interop” было установлено в true.

Класс MWO1 (middleware-объект) наследовался от System.EnterpriseServices.ServicedComponent и интерфейса ITest, описанного в той же библиотеке, что и объект MWO1 (файл «MWO1.cs»). Вот основной код описаний из этого файла:

Некоторые изменения были внесены и в файл «AssemblyInfo.cs» (в проекте middleware-объекта). Ниже приведено содержание этого файла:

После компиляции библиотеки она была зарегистрирована в GAC (global assembly cache) утилитой gacutil.exe. Эта утилита может быть найдена в подкаталоге FrameworkSDK\Bin корневого каталога Visual Studio NET. Командные строки регистрации приведены ниже:

При регистрации в GAC библиотека копируется в отдельный каталог (кэшируется). Поэтому после ее перекомпиляции нужно отрегистрировать старую версию (при этом она удаляется из кэша) и только затем зарегистрировать новую, иначе изменения «не будут замечены» (будет загружаться старый объект из кэшированной библиотеки).

Помимо регистрации в GAC объекты из библиотеки SpeedTest_ADONet_server.dll были зарегистрированы в COM+ через утилиту regsvcs, которая может быть найдена в подкаталоге Microsoft.NET\Framework\v1.0.3705 системного каталога (разумеется, номер версии не обязательно будет 1.0.3705). Командная строка регистрации приведена ниже:

Для регистрации на удаленном компьютере (клиенте) средствами COM+ (system32\Com\comexp.msc) был создан proxy. Этот proxy был установлен на клиентской машине. Туда же было скопировано клиентское приложение и библиотека SpeedTest_ADONet_server.dll.


Для работы через COM+ в коде приложения было реализовано создание удаленного middleware-объекта MWO1. Ниже приведен пример кода создания этого объекта:

«Локальный режим через NET Remoting»

Принцип имитации forward-only-курсора (получения и передачи данных) тот же, что и в «локальном режиме через COM+», т.е. создается промежуточный (middleware) объект, работающий с БД, и клиентское приложение, обращающееся к нему. В этом случае данные копируются «через процесс» (выполняется маршалинг). Однако механизм взаимодействия изменился – используется NET Remoting вместо COM+. В чем проявляются отличия?

Во-первых, вместо регистрации в COM+, m />).

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

Конфигурация сервера из файла SpeedTest_ADONet_RemotingServer.exe.config приведена ниже:

В этой же области видимости (namespace) был реализован объект Server, в котором и была реализована вся функциональность работы с базой данных. Ниже приведен его код:

«Удаленный режим через COM+»

Принцип имитации forwardonly-курсора (получения и передачи данных) тот же, что и в «локальном режиме через COM+» теста «Forward». На клиентской машине устанавливается proxy серверного COM+-приложения.

«Удаленный режим через NET Remoting»

Принцип имитации forwardonly курсора (получения и передачи данных) тот же, что и в «локальном режиме через NET Remoting» теста «Forward».

Тест «Forward», ADO


«In-process режим»

В качестве forward-only курсора использовался объект Recordset с установкой значений свойств: CursorType в ADOpenForwardOnly, LockType в adLockReADOnly и CursorLocation в adUseServer. Размер кэша устанавливался равным 100 записям (свойство CacheSize). Переход по записям осуществлялся с помощью вызова метода MoveNext.

Основной код теста приведен ниже:

«Локальный режим через COM+»

Поскольку в ADO отсутствует возможность получения отключенного однонаправленного курсора, обеспечение передачи данных в forward-only режиме между процессами или по сети оказалось затруднительным. Конечно, можно было бы немножко попрограммировать, и посылать на клиента порции данных, запакованные в отдельные отключенные объекты Recordset, собирая их по прибытии в один большой Recordset. Однако в качестве примера это уже было сделано в тесте ADO.NET – повторение не представляет особого интереса (принцип ясен).

Копирование же всего курсора между процессами или по сети представляется нецелесообразным (в таблице – миллион записей). Однако, для чистоты эксперимента, такой опыт все же был проведен.

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

В коде клиентской стороны произошло единственное изменение: для переоткрытия курсора вместо последовательного вызова методов Close и Open от объекта m_rs (см. код примера теста «Forward» в «in-process режиме») стал вызываться метод Orders1000000SelectAll middleware-объекта. Код middleware-объекта приведен ниже (код инициализации и метод GetDisconnectedCursor применялся и в остальных тестах ADO, поэтому в дальнейшем тексте будут ссылки сюда):

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «Forward». На клиентской машине устанавливается proxy серверного COM+-приложения.

Значение времени выполнения этого теста получено не вполне корректно, поскольку где-то к его середине система сообщила пренеприятнейшее известие: ”low virtual memory”. Очевидно, что если бы не это ужасное событие, то тест выполнился бы быстрее.

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

Тест «Forward», ascDB


«In-process режим»

В качестве forward-only курсора использовался объект ascVisualCursor с установкой значений свойств rsDBCursorType равным actForward. Размер кэша устанавливался равным 100 записям (свойство rsFetchBufferSize). Переход по записям осуществлялся с помощью вызова метода FetchNext.

Вся работа с SQL-сервером уже на этом этапе вынесена в промежуточный объект, но библиотека с этим объектом зарегистрирована локально (не через COM+), то есть загружается в процессе клиентского приложения (in-process). Для получения курсора клиентское приложение вызывает метод middleware-объекта, в котором загружается и выполняется предварительно настроенная «хранимая команда» ascDB. Хранимая команда ascDB – это команда, хранимая на диске в виде файла. Она может быть создана и записана с помощью дизайнера команд. Результатом выполнения команды является курсор (объект ascCachedCursor). Этот объект передается в клиентское приложение в качестве возвращаемого параметра вызванного метода middleware-объекта и может подключаться к визуальному курсору.

Вызов метода middleware-объекта и подключение кэширующего курсора (ascCachedCursor) к визуальному курсору автоматизирован и настраивается на странице свойств визуального курсора, поэтому соответствующий код отсутствует в статье. Однако вместо визуального курсора в ascDB можно воспользоваться кэширующим курсором. В этом случае для получения данных (передаваемых в объекте ascCachedCursor) нужно явно (из кода программы) вызывать методы middleware-объекта. Затем, также программно, нужно подключать полученный полученный ascCachedCursor к визуальному курсору, который связан с элементами управления, отображающими данные (ascDataGrid и ascDataField).

В ascDB существует также возможность работы напрямую с базой данных – минуя middleware-объект и обходясь без команд. Для этого надо непосредственно в коде клиентского приложения реализовать работу через объект ascServer. Пример такого кода можно увидеть в тестах «Top10» и «Top100» ascDB.

Однако наилучшим образом проиллюстрировать многоуровневую архитектуру ascDB позволяет именно использование middleware-объекта и хранимых команд. Кроме того, такой подход позволяет практически всю работу выполнить визуально и является типичным для ascDB.

Ниже приведен основной код теста (через объект scVisualCursor):

«Локальный режим через COM+»

Принцип получения и передачи данных остался тем же, что и в in-process режиме: для передачи данных между процессами использовался объект ascCachedCursor, в котором содержались (кэшировались) все данные, полученные в результате запроса к SQL-серверу.

Короче говоря, все полностью так же, как и в «in-process режиме», но библиотека с промежуточным объектом зарегистрирована в COM+-приложении.

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «Forward». На клиентской машине устанавливается proxy серверного COM+-приложения.

Тест «Forward». Результаты


Test Forward (10 итераций) InProcessClient COM+ Client NET Remoting Client COM+ Server NET Remoting Server
ADO.NET 51.77 54.238 (ручная реализация поблочного копирования данных) 54.390 (ручная реализация поблочного копирования данных) 57.89 (ручная реализация поблочного копирования данных) 56.281 (ручная реализация поблочного копирования данных)
ADO 0.052 (приведено к 10 итерациям, получено по 1000) 330.76 (1 итерация) не тестировалось 439.39 (1 итерация) не тестировалось
ascDB 0.17 0.231 не тестировалось 1.632 не тестировалось

Пусть вас не удивляет малая разница во времени выполнения теста ADO.NET между разными режимами, поскольку это время в основном определяется временем переоткрытия объекта SqlDataReader на серверной стороне. Столь большое время переоткрытия объекта DataReader связано с кэшированием им всей таблицы (объяснения этому см. выше). По сравнению с этим событием передача по сети блока из 100 записей (не забывайте, что мы реализовали вручную поблочное копирование) практически не занимает времени. Разницы между in-process, клиентскими и серверными режимами в тестах ADO.NET практически нет.

Однако имитация forwardonly-курсора через копирование объектов DataSet с порционной выдачей resultset’a по 100 строк (код см. выше) позволила хоть как-то работать с такими объемами данных по сети, хотя отставание ADO.NET от ascDB и в этом случае впечатляет. Даже в in-process режиме ADO.NET работает в тестируемом режиме неприемлемо медленно.

Никто и не сомневался, что в отключенном от БД режиме получить на клиента миллион записей будет трудно. Однако, пусть в невероятный срок, но ADO все-таки справилось с этой нелегкой задачей! А если серьезно, то, разумеется, работа в отключенном режиме (а для ADO.NET это идеологически единственный режим) с такими объемами данных невозможна. Да и в реальности вряд ли кому-то придется иметь дело с таблицей на миллион или даже 100 тыс. записей – такие условия скорее являются исключением, нежели правилом.

Приходится констатировать, что на ADO.NET невозможно организовать эффективную докачку данных, тогда как на ADO это сделать можно, а ascDB делает это автоматически. Наш совет пользователям ADO.NET: старайтесь выбирать столько данных, сколько будет обработано (ограничивая запрос средствами SQL), или выбирайте все данные resultset’a, потому как все равно все данные вашего resultset’a будут выбраны в кэш.

Тест «LargeKeySet»

Выполнялся запрос на выборку всех записей из таблицы, содержащей 100000 записей, с последующим чтением записей из разных позиций (перемещение методом FetchRandom или его аналогом в позиции 10, 75, 30, 50 процентов от количества записей, а затем в конец и на начало списка). Использовались keyset-курсоры (static-курсоры в не-InProcess режимах ADO и SqlDataAdapter в ADO.NET). Каждый переход на новую строку сопровождался считыванием из нее данных, как это описано выше (в тесте «Forward»). Затем выполнялось переоткрытие курсора. Выполнялось 10 повторов.

Тест «LargeKeySet». ADO.NET


«In-process режим»

Доступ к данным осуществлялся через SqlDataAdapter, данные из которого копировались в DataSet (с использованием метода SqlDataAdapter.Fill).

Основной код примера приведен ниже. Здесь выполняется переоткрытие объекта SqlDataAdapter с перезаполнением объекта DataSet. Хотя прокрутка массива данных в DataSet с их получением выполняется очень быстро (по сравнению с заполнением объекта DataSet), она была выполнена:

«Локальный режим через COM+»

Объект DataSet, заполненный методом SqlDataAdapter.Fill, возвращался в клиентское приложение из промежуточного (middleware) объекта. Действие это оказалось небыстрым и очень неэкономичным в отношении оперативной памяти. Система перешла в состояние ”low virtual memory”, где и случился вылет с сообщением: «System.OutOfMemoryException: Exception of type System.OutOfMemoryException was thrown».

Клиентская часть этого теста отличается от вышеописанного теста in-process режима только реализацией метода CursorReopenInternal. Вместо открытия объекта SqlDataAdapter и заполнения объекта DataSet через него, вызывается метод middleware-объекта. Вот основной код этого теста:

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «LargeKeySet». На клиентской машине устанавливается proxy серверного COM+-приложения.

Получена ошибка с сообщением о переполнении памяти («OutOfMemoryException was thrown»).

«Удаленный режим через NET Remoting»

Принцип получения и передачи данных тот же, что и в «локальном режиме через NET Remoting» теста «LargeKeySet». На клиентской машине устанавливается proxy серверного COM+-приложения.

Получена ошибка с сообщением о переполнении памяти («OutOfMemoryException was thrown»).

Тест «LargeKeySet», ADO


«In-process режим»

В качестве keyset курсора использовался объект Recordset с установкой значений свойств CursorType равным ADOpenKeyset, LockType равным adLockReADOnly и CursorLocation равным adUseServer. Размер кэша устанавливался равным 100 записям (свойство CacheSize)..

Основной код теста мало отличается от аналога, реализованного для ADO.NET. По сути отличий три. Первое: реализация не на C#, а на VB6. Второе: переоткрытие курсора выполнялось вызовом метода CursorReopen, описанного в тесте «Forward» для «in-process режима». Третье: переход по записям осуществлялся с помощью вызова метода Move.

В связи с этим пример кода метода вызова теста приведен не будет. Код создания и открытия соединения приведен выше (в описании локального режима тестирования через COM+ для теста «Forward»).

«Локальный режим через COM+»



Для передачи данных между процессами использовался объект Recordset, отключенный от SQL-сервера (disconnected). Для получения отключенного Recordset ему перед открытием устанавливались значения свойств CursorLocation равным adUseClient, CursorType равным ADOpenStatic, LockType равным adLockBatchOptimistic. Размер кэша устанавливался равным 100 записям (свойство CacheSize). После открытия курсора и заполнения объекта Recordset он (Recordset) отключался от SQL-сервера (значение свойства ActiveConnection устанавливалось равным Nothing) и возвращался в клиентское приложение.

Пример кода метода GetDisconnectedCursor приведен в описании теста «Forward» в «локальном режиме через COM+».

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «LargeKeySet». На клиентской машине устанавливается proxy серверного COM+-приложения.

Тест «LargeKeySet», ascDB


«In-process режим»

В качестве keyset-курсора использовался объект ascVisualCursor с установкой значений свойства rsDBCursorType равным actKeyset. Размер кэша устанавливался равным 100 записям (свойство rsFetchBufferSize). Переход по записям осуществлялся с помощью вызова метода FetchRandom. В общем, принципы работы ничем не отличались от примененных в тесте «Forward». Реализация тестовых методов совпадает с аналогичными реализациями для теста ADO, за исключением того, что методы навигации по курсору в ascDB называются FetchXXX, а не MoveXXX.

Вся работа с сервером уже на этом этапе вынесена в промежуточный объект, но библиотека с этим объектом зарегистрирована локально (не через COM+).

«Локальный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «LargeKeySet». Middleware-объект зарегистрирован в COM+.

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+». На клиентской машине устанавливается proxy серверного COM+-приложения.

Тест «LargeKeySet». Результаты


Test LargeKeyset (10 итераций) InProcessClient COM+ Client NET Remoting Client COM+ Server NET Remoting Server
ADO.NET 38.816 Out of memory Out of memory Out of memory Out of memory
ADO 4.226 47.638 не тестировалось 226.065 не тестировалось
ascDB 7.921 8.012 не тестировалось 11.577 не тестировалось
Таблица 2 Результаты теста LargeKeySet

Из результатов теста следует, что с работой по сети с большими объемами данных в keyset-режиме ADO.NET не справляется, тогда как ascDB показало себя неплохо. Это и не странно, т.к. ascDB – единственное из тестировавшихся средство работы с БД для многоуровневых приложений, полноценно реализующее эмуляцию keyset-курсора в удаленном режиме. В in-process режиме ADO оказалось в полтора раза быстрее ascDB. Для ascDB же не обнаружилось большой разницы, работать ли на клиенте или по сети – выполнение теста на удаленной машине оказалось медленнее клиентского теста менее чем в полтора раза.

Естественно, такие результаты ADO.NET невольно вызывают вопрос: что случилось? Как это может быть? Мы провели смелый научный эксперимент, в ходе которого выяснилось, что основная причина тормозов в ADO.NET связана с невероятно неоптимальной сериализацией данных. Мы создали простой тест, в котором сначала заполняли DataSet и измеряли скорость его работы. Естественно, что его время совпадало со временем работы теста in-process. Собственно, вот код этого теста:

Затем мы дополнили тест ручным вызовом сериализации в бинарный формат (код приведен ниже):

Каково же было наше удивление, когда в результате выполнения этого кода было занято несколько сотен мегабайт памяти, и машина погрузилась в глубокое раздумье. Тогда мы попытались скопировать данные в массив структур и сериализовать уже его. Объем занимаемой памяти несколько уменьшился, но время выполнения теста все равно оказалось совершенно неудовлетворительным. Тогда мы попытались сериализовать содержимое DataTable вручную (код приведен ниже):

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

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

Тест «ChangeData»

Выполнялся запрос на выборку всех записей из таблицы, содержащей 10 тыс. записей. После получения списка записей с ним выполнялись действия, имитирующие реальную работу (перебор, добавление, изменение, удаление записей, сохранение и переоткрытие курсора). Каждый переход на новую строку сопровождался считыванием из нее данных, как это описано выше (в тесте «Forward»). Использовались keyset-курсоры или их аналоги (SqlDataAdapter в ADO.NET). Выполнялось 10 повторов. После каждого повтора содержимое таблицы БД восстанавливалось.

ПРЕДУПРЕЖДЕНИЕ

К сожалению, при тестировании средств доступа к базам данных (ADO.Net, ADO, ascDB) в данном тесте было допущено несколько ошибок. См. поправки к статье.

Тест «ChangeData», ADO.NET


«In-process режим»

Доступ к данным осуществлялся через SqlDataAdapter, данные из которого копировались в DataSet (с использованием метода SqlDataAdapter.Fill). Выполнялись операции вставки, удаления и модификации данных в объекте DataSet с записью изменений в таблицу Orders10000.

Методы CursorFetchNext и CursorFetchPrev имитировались через CursorFetchRandom (последний описан выше, в «in-process режиме» теста «LargeKeySet» для ADO.NET).

Основной код теста «ChangeData» приведен ниже:

«Локальный режим через COM+»

Объект DataSet после создания и заполнения возвращался в клиентское приложение. Изменения в данных, произведенные в клиентском приложении, копировались в другой объект DataSet (содержащий только изменения), который передавался в middleware-объект. Уже там изменения вносились в базу данных методом SqlDataAdapter.Update (пример кода приведен ниже):

«Локальный режим через NET Remoting»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM», но используется технология NET Remotimg.

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+». На клиентской машине устанавливается proxy серверного COM+-приложения.

«Удаленный режим через NET Remoting»

Принцип получения и передачи данных тот же, что и в «локальном режиме через NET Remoting». Клиентское приложение запускается на локальной машине, серверная часть – на серверной.

Тест «ChangeData», ADO


«In-process режим»

В качестве keyset-курсора использовался объект Recordset (настройки аналогичны «in-process режиму» для теста ADO «LargeKeySet», см. выше). Алгоритм работы теста «ChangeData» полностью соответствует аналогичному тесту для ADO.NET, разница лишь в языке кодирования (тест ADO.NET писался на C#, а ADO – на VB6), поэтому код примера здесь не приводится.

«Локальный режим через COM+»

Для передачи данных между процессами использовался объект Recordset, отключенный от SQL-сервера (настройки и принципы передачи данных те же, что и в вышеописанном «локальном режиме через COM+» теста «LargeKeySet»).

Для записи изменений в middleware-объект возвращался Recordset, содержащий строки с измененными данными. Cвойство MarshalOptions этого объекта устанавливалось равным adMarshalModifiedOnly, чтобы копировать (передавать между процессами или по сети) не все строки, а только измененные.

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+».

Тест «ChangeData». ascDB


«In-process режим»

Принцип получения и передачи данных тот же, что и в «in-process режиме» теста «LargeKeySet». Код теста для краткости не приводится, так как он аналогичен коду текста для ADO за исключением того, что использовались объекты ascDB.

«Локальный режим через COM+»

Принцип получения и передачи данных тот же, что и в «локальном режиме через COM+» теста «LargeKeySet».

«Удаленный режим через COM+»

Принцип получения и передачи данных тот же, что и в «удаленном режиме через COM+» теста «LargeKeySet».

Тест «ChangeData». Результаты


ChangeData (10 итераций) InProcessClient COM+ Client NET Remoting Client COM+ Server NET Remoting Server
ADO.NET 7.731 187.57 174.86 1251.2 1141.14
ADO 26.718 (2.574) 5.178 не тестировалось 26.278 не тестировалось
ascDB 13.519 13.79 не тестировалось 36.933 не тестировалось
Таблица 3. Результаты теста ChangeData.
ПРИМЕЧАНИЕ

В таблице 3 с результатами для in-process теста ADO в скобках приведено значение, полученное при отключенном Recordset.

Как видно по результатам тестирования, лучше всех с задачей в in-process режиме справляется ADO в отключенном режиме. Превосходство над «ближайшим преследователем» (ADO.NET) – в 3 раза. При этом то же ADO, но без отключения от БД, оказывается аутсайдером. Разница между подключенным к БД и отключенным режимами – 10 раз! Как оказалось, ADO безбожно тормозит на операции прокрутки курсора в in-process режиме (т.е. без отключения от БД, см. результаты в таблицах ниже).

ADO.NET в In-process режиме было примерно вдвое быстрее, чем ascDB. Столь нешустрая работа ascDB в in-process режиме связана в основном с большой длительностью записи изменений.

В целом очевидно превосходство ADO (в отключенном режиме) над ADO.NET и ascDB.

Ниже приведена детализация результатов этого теста по операциям:

In-process режим


Test ChangeData Insert Update Delete Fetch Save Reopen Всего
ADO.NET 0.01 0.01 0.01 0.01 4.898 2.793 7.731
ADO (connected) 0.07 0.382 12.82 11.814 1.001 0.601 26.688
ADO (disconnected) 0.121 0.11 0.02 0.02 0.38 1.923 2.574
ascDB 0.14 0.232 0.01 1.082 11.074 0.931 13.469
Таблица 4. Результаты теста ChangeData по операциям. Режим in-process.

ПРИМЕЧАНИЕ

В таблице 4 строка «ADO (connected)» содержит данные для DataSet, подключенного к БД. Строка «ADO (disconnected)» содержит данные для DataSet, отключенного от БД.

Из таблицы 4 видно, что при отключении объекта DataSet от БД в тесте ADO заметно увеличивается время переоткрытия курсора, но зато резко снижаются затраты времени на операции удаления записей и прокрутки курсора. В результате общее время выполнения теста ADO снижается в 10 раз. Это связано с потерями времени на прокручивание подключенного курсора и удаление записей! Даже передача такого объекта по сети оказалась всего лишь вдвое медленнее, чем его прокрутка в «in-process режиме» (т.е. в подключенном к БД состоянии).


Также заметно, что в ascDB наибольшее время занимает операция записи изменений (это явная ошибка, с которой нам в ближайшее время придется побороться).

Локальный режим через COM+


Insert Update Delete Fetch Save Reopen Всего
ADO.NET 0.01 0.01 0.01 0.8 67.59 119.07 187.49
ADO 0.12 0.12 0.03 0.49 4.418 5.178
ascDB 0.21 0.28 0.03 1.241 11.021 0.978 13.76
Таблица 5. Результаты теста ChangeData по операциям. Локальный режим через COM+.

За счет сериализации, а также копирования данных между процессами, на локальной машине резко (в 4.5 раза) возрастает время выполнения теста ADO.NET. Время выполнения ADO-теста возрастает вдвое (по отношению к тесту с отключением DataSet от базы в inprocess-режиме), но при этом ADO не теряет первого места. Время, затрачиваемое на тест ascDB, практически не изменяется, что свидетельствует о высокой скорости передачи данных между процессами, но, одновременно, об относительно низкой скорости записи изменений (если бы не запись, тест ascDB занимал бы 2.5 секунды вместо 14).

Удаленный режим через COM+


TestOrders10000 Insert Update Delete Fetch Save Reopen Всего
ADO.NET 0.1 0.2 0.1 0.1 565.22 685.68 1251.4
ADO 0.06 0.38 0.04 2.583 23.914 26.977
ascDB 0.07 0.591 0.03 15.722 17.997 1.783 36.193
Таблица 6. Результаты теста ChangeData по операциям. Удаленный режим через COM+.

С переносом клиентского приложения на удаленную машину время выполнения теста ADO.NET возросло еще в 8 раз (по отношению к клиентскому режиму через COM+). Определенно, разработчики .NET занимают память не скупясь, и сериализуют данные талантливо! Время выполнения теста ADO возросло в 5 раз, но ADO и здесь оказалось лучшим.

Тест ascDB выполнился в 3 раза медленнее, чем клиентский вариант, но все-таки не догнал ADO, отстав от последнего в быстродействии примерно в 1.5 раза. Значительное возрастание времени на операции прокрутки (fetch) в удаленном тесте ascDB легко объяснимы – keyset-курсор выполняет докачку данных (то есть обращается к серверу по сети) именно на операциях прокрутки. Поскольку и ADO.NET, и ADO в удаленном тесте полностью копировали данные всего resultset’a, то основная нагрузка в этих тестах легла на операции переоткрытия и записи изменений (соответственно колонки Reopen и Save таблицы 6).

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

Тесты «Top 10» и «Top 100».

Выполнялся запрос на выборку и перебор 10 (или 100, соответственно) первых записей из таблицы. Размер resultset’а ограничивался в запросе (запрос вида «Select Top N From TableName»). Каждый переход на новую строку сопровождался считыванием из нее данных, как это описано выше (в тесте «Forward»). Затем выполнялось переоткрытие курсора. Использовались forward-only курсоры или их аналоги. Размер кэширующего буфера объектов ascCachedCursor (ascDB) и Recordset (ADO) устанавливался равным считываемому количеству строк (10 в тесте Top10 и 100 в тесте Top100). Выполнялось 100 повторов (в случае, когда время выполнения теста оказывалось слишком маленьким, тест повторялся с увеличением количества итераций, а результат получался делением).

Данный тест наилучшим образом подходит для disconnected-идеологии, а, следовательно, ADO.NET должен был показать себя с наилучшей стороны (т.к. ADO.NET спроектирован исключительно для disconnected-работы). Наши надежды не оправдались, но об этом чуть позже (в выводах из тестов).

Тесты «Top 10» и «Top 100». ADO.NET

Принципы получения и передачи данных соответствуют аналогичным режимам теста «ChangeData».

Примеры кода для теста «Top 10» приведен ниже (тест «Top 100» отличается только SQL-запросом):

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

// подключаем SQL ADO.NET
using System.Data.SqlClient;

namespace ConsoleApplication1
<
class Program
<
static void Main( string [] args)
<
// connection string (описано выше: шаг №4)
string connectionString = @ «Data Source=EVGENI; Initial Catalog=MyDatabase1; Integrated Security=True» ;

// connect to db
using (SqlConnection connection = new SqlConnection(connectionString))
<
// open db
connection.Open();
>
>
>
>

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. Для этого:

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

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

В этом случае проверьте правильность введенного пути к файлу
базы данных и, возможно, уточните пароль;

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

На этом работа по созданию объекта 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();

this.oleDbConnection1.ConnectionString =
@»Prov ;User > 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 DB SQL Значение по умолчанию
ConnectionString Строка соединения System.String RW + +
ConnectionTimeout Время ожидания соединения в секундах System.Int32 R + + 15 сек
Database Имя текущей базы данных (или той, которая будет использоваться при открытии соединения) System.String R + +
DataSource Имя сервера баз данных (SQL) или спецификация файла с данными System.String R + +
PacketSize Размер сетевого пакета в байтах System.Int32 R + 8192
Provider Имя провайдера OLE DB System.String R +
ServerVersion Версия сервера баз данных System.String R + +
State Битовая комбинация значений ConnectionState ConnectionState R + + Closed
WorkstationId Строка, идентифицирующая клиента System.String R + Имя клиентского компьютера

Те, кто знаком с классическим 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»
и
«Close» ), а также показывать состояние и свойства соединения
(кнопка «Show» ). Программа может быть откомпилирована и выполнена в среде
Visual Studio .NET или .NET Framework.

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

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

<
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();
>

Три стороны технологии ADO.NET

Читайте также:

  1. ADO.NET
  2. CALS-технологии
  3. CALS-технологии
  4. CALS-технологии
  5. CASE-технологии
  6. Ethernet — пример стандартной технологии коммутации пакетов
  7. I. Технологии менеджмента качества
  8. II.Затраты на организацию работ на строительных площадках и усовершенствование технологии
  9. OLAP-технологии
  10. PDM-системы и технологии
  11. PLM-технологии
  12. Strengths (Сильные стороны), Weaknesses (Слабые стороны), Opportunities (Возможности) и Threats (Угрозы).

Библиотеки ADO.NET (.NET версии 3.5 и выше) можно применять тремя концептуально различными спосо­бами: в подключенном (связном) режиме, в автономном режиме и с помощью технологии Entity Framework. В .NET версии 2.0 используются лишь два первых способа взаимодействия.

При использовании подключенного уровня (connected layer), кодовая база явно подключается к соответствующему хранили­щу данных и отключается от него. При таком способе использования ADO.NET обычно происходит взаимодействие с хранилищем данных с помощью объектов подключения, объектов команд и объектов чтения данных.

Автономный уровень (disconnected layer), по­зволяет работать с набором объектов DataTable (содержащихся в объекте DataSet), который представляет на стороне клиента копию внешних данных. При получении DataSet с помощью соответствующего объекта адаптера данных подключение открывается и за­крывается автоматически. Понятно, что этот подход помогает быстро освобождать под­ключения для других вызовов и повышает масштабируемость систем.

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

После выпуска .NET 3.5 SP1 в ADO.NET появилась поддержка новой технологии (новой функции API), которая на­зывается Entity Framework (сокращенно EF). Технология EF показывает, что многие низ­коуровневые детали работы с базами данных скрыты от программиста и отрабатываются за него при генерации соответствующего LINQ-запроса. Технологию LINQ рассмотрим в конце изучения темы.

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

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

3.1 Поставщики данных ADO.NET.ADO.NET не предлагает единого набора типов для связи со всеми СУБД. Вместо этого в ADO.NET имеются различные поставщики данных (провайдеры данных – data provider), каждый из которых оптимизирован для взаимодействия с конкретной СУБД. Первая выгода этого подхода состоит в том, что можно запрограммировать особый поставщик данных для доступа к любым уникальным особенностям конкретной СУБД. Еще одна выгода — конкрет­ный поставщик данных может напрямую подключиться к механизму соответствующей СУБД, не пользуясь междууровневым слоем отображения.

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

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

В рамках .NET Framework поставляется набор поставщиков данных, например, поставщик в стиле Oracle, Microsoft SQL Server и OLE DB/ODBC (рис. 1):

Рисунок 1. – Уровни модели поставщиков данных

Поставщик SQL Server.NET Data Provider предоставляет оптимизированный доступ к базе данных Microsoft SQL Server (версии 7.0 и выше) и взаимодействует с ней напрямую по «родному» протоколу передачи данных SQL Server. Он расположен в пространстве имен System.Data.SqlClient. Поставщик OLE DB предоставляет доступ к любому источнику данных, который имеет драйвер OLE DB. Это включает базы данных SQL Server версий, предшествующих 7.0. Он расположен в пространстве имен System.Data.OleDb. Поставщик Oracle предоставляет оптимизированный доступ к базам данных Oracle (версии 8 и выше).

Примечание.Если ваше приложение работает с СУБД Microsoft Access, то следует подключить следующие директивы использования пространства имен:

Если ваше приложение работает с СУБД Microsoft SQL Server, то следует подключить следующие директивы использования пространства имен:

При выборе поставщика сначала необходимо пытаться найти встроенный поставщик ADO.NET, который предназначен для имеющегося источника данных. Если таковой не найден, можно воспользоваться OLE DB при наличии драйвера OLE DB для источника данных.

Любой используемый поставщик данных определяет набор типов, обеспечивающих базовые функциональные возможности. Базовые объекты поставщика данных ADO.NET, их базовые классы определены в пространстве имен System.Data.Common:

Тип объекта Базовый класс Реализован–ные интерфейсы Назначение
Connection SqlConnection DbConnection OracleConnection IDbConnection Объект соединения. Позволяет подключаться к хранилищу данных и отключаться от него. Кроме того, объекты подключения обеспечивают доступ к соответствующим объектам транзакций.
Command DbCommand SqlCommand IDbCommand Объект команды. Представляет SQL-запрос или хранимую процедуру. Кроме того, объекты команд предоставляют доступ к объекту чтения данных конкретного поставщика данных.
DataReader DbDataReader IDataReader, IDataRecorder Объект чтения данных. Предоставляет однонаправленный доступ к данным только для чтения на стороне сервера.
DataAdapter DbDataAdapter SqlDataAdapter, OracleDataAdapter IDataAdapter, IDbDataAdapter Объект адаптера данных. Пересылает наборы данных из хранилища данных к вызывающему процессу и обратно. Адаптеры данных содержат подключение и набор из четырех внутренних объектов команд для выборки, вставки, изменения и удаления информации в хранилище данных.
Parameter DbParameter SqlParametrs IDataParameter, IDbDataParameter Объект параметра. Представляет именованный параметр в параметризованном запросе.
Transaction DbTransaction SqlTransaction IDbTransaction Объект транзакции. Выполняет транзакцию базы данных.

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

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

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

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

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

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

4. Объектная модель ADO.NET. Одни лишь подключенные приложения не удовлетворяют всем требованиям, предъявляемым к современным распределенным приложениям. В автономных приложениях, созданных с помощью ADO.NET, используют иной подход. Для обеспечения автономности используются объекты DataAdapter. Они осуществляют выполнение запросов, используя для этого объекты подключения. А результаты выполнения, то есть данные, передаются автономным объектам.


Благодаря такому принципу автономные объекты не знают о существовании объектов подключения, так как напрямую не работают с ними. Таким образом, реализация объекта, хранящего данные, не зависит от конкретного поставщика данных, а именно от СУБД. Поскольку конкретная реализация адаптера данных зависит от соответствующего источника данных, конкретные адаптеры данных реализованы в составе конкретных поставщиков.

Автономные приложения обычно подключаются к базе как можно позже и отключаются как можно раньше. Важным элементом в такой схеме подключения и предоставления автономного доступа к данным является контейнер для табличных данных, который не знает о СУБД. Такой незнающий о СУБД автономный контейнер для табличных данных представлен в библиотеках ADO .NET классом DataSet или DataTable.

Объектная модель ADO .NET представлена на рисунке:

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

Рисунок 2. – Классы ADO.NET

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

Таким образом, архитектуру ADO.NET можно разделить на две фундаментальные части: подключаемую и автономную. Все классы в ADO.NET можно поделить по этому критерию. Единственное исключение – класс DataAdapter, который является посредником между подключенной и автономной частями ADO.NET.

Краткий обзор объектов ADO .NET:

Источник данных DataSet. Это специализированный объект-образ базы данных, представляющий собой локальные копии любого количества взаимосвязанных таблиц данных. Класс DataSet является ядром автономного режима доступа к данным в ADO.NET. Лучше всего рассматривать его с позиции, как будто в нем есть своя маленькая СУБД, полностью находящаяся в памяти.

DataSet состоит из объектов типа DataTable и объектов DataRelation. В коде к ним можно обращаться как к свойствам объекта DataSet. Свойство Tables возвращает объект типа DataTableCollection, который содержит все объекты DataTable используемой базы данных.

Таблицы и поля (объекты DataTable и DataColumn). Объекты DataTable используются для представления одной из таблиц базы данных в DataSet. В свою очередь, DataTable составляется из объектов DataColumn. DataColumn – это блок для создания схемы DataTable. Каждый объект DataColumn имеет свойство DataType, которое определяет тип данных, содержащихся в каждом объекте DataColumn. Например, тип данных может быть целым числом, строковым данным, логическим данным и т.д. Поскольку данные, содержащиеся в DataTable, обычно переносятся обратно в исходный источник данных, необходимо согласовывать тип данных с источником.

Строки (объект DataRow). Коллекция Rows объекта DataTable возвращает набор строк (записей) заданной таблицы. Эта коллекция используется для изучения результатов запроса к базе данных. Мы можем обращаться к записям таблицы как к элементам простого массива.

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

Объект DataAdapter. Для осуществления взаимодействия между DataSet и собственно источником данных используется объект типа DataAdapter. Само название этого объекта – адаптер, преобразователь, – указывает на его природу. DataAdapter содержит методы Update() и Fill() для обновления данных из базы и заполнения объекта DataSet.Можно использовать четыре команды объекта, чтобы получить любые обновления: UpdateCommand, InsertCommand, DeleteCommand и SelectCommand.

На следующем рисунке показано использование объекта SQLDataAdapter для передачи данных между базой данных SQL Server и объектом DataSet:

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

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

В пространстве имен System.Data.Common определено множество абстрактных типов, которые обеспечивают общий интерфейс для всех управляемых провайдеров. Все управляемые провайдеры реализуют интерфейс IDbConnection, который используется для конфигурирования и открытия сеанса подключения к источнику данных. Типы, которые реализуют другой интерфейс — IDbCommand, используются для выполнения SQL-запросов к базам данных. Интерфейс IDataReader обеспечивает считывание данных при помощи однонаправленного курсора только для чтения. Типы, которые реализуют IDbOataAdapter, ответственны за заполнение объекта DataSet данными из базы данных.

Итак, интерфейс IDbConnection реализуется объектом соединения поставщика данных. Этот интерфейс определяет множество членов, используемых для настройки соединения с конкретным хранилищем данных (например, свойство для строки соединения string ConnectionSrting), а также позволяет получить объект транзакции поставщика данных. Перегруженные методы IdbTransaction BeginTransaction() и IdbTransaction BeginTransaction(Isolation Level il), определенные в интерфейсе IDbConnection, обеспечивают доступ к объеку транзакции поставщика данных.

Объект соединения Connection. Объекты подключения используются для связи с базами данных. Они обладают свойствами, такими как DataSource, UserID, и Password, которые необходимы для доступа к DataSource. Команды перемещаются по соединению, и множества результатов возвращаются в виде потоков, которые могут быть прочитаны DataReaders или помещены в объекты DataSet. Есть два вида соединения объектов в ADO.NET: SqlConnection и OleDbConnection.

Объекты Command. Командные объекты содержат информацию, которая передается в базу данных. Команда может быть сохранена как вызов процедуры, оператор обновления или утверждения, который возвращает результаты. Можно также использовать входные и выходные параметры и возвращаемые значения. В ADO.NET можно использовать два вида командных объектов: SqlCommand и OleDbCommand.

Объекты DataReader. DataReader – это в своем роде синоним представления только читаемых/только передаваемых данных. Программный интерфейс DataReader поддерживает иерархические данные. Объект DataReader возвращается после выполнения команды в базе данных. Например, можно использовать DataReader для просмотра списка результатов поиска на веб-странице. ADO.NET включает два типа объектов DataReader: SqlDataReader для данных Microsoft SQL Server версии 7.0 (или более поздней версии), и OleDbDataReader для данных ADO. Объект DataReader является отдельной базой данных. Поведение SqlDataReader может отличаться от поведения OleDbDataReader. Для передачи данных в DataReader используются объекты OleDbCommand или SqlCommand и метод ExecuteReader.

| следующая лекция ==>
Лекция 3. 1. Социальная структура общества: понятие основные элементы, факторы формирования | Понятие и сущность источников МТП

Дата добавления: 2014-01-13 ; Просмотров: 2309 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

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

Контакты • DVD Maker • Факсы и сканирование • Internet Explorer • Журнал • Экранная лупа • Media Center • Проигрыватель Windows Media • Программа совместной работы • Центр устройств Windows Mobile • Центр мобильности • Экранный диктор • Paint • Редактор личных символов • Удалённый помощник • Распознавание речи • WordPad • Блокнот • Боковая панель • Звукозапись • Календарь • Калькулятор • Ножницы • Почта • Таблица символов • Исторические: Movie Maker • NetMeeting • Outlook Express • Диспетчер программ • Диспетчер файлов • Фотоальбом

Chess Titans • Mahjong Titans • Purble Place • Пасьянсы (Косынка • Паук • Солитер) • Сапёр • Пинбол • Червы

Autorun.inf • Фоновая интеллектуальная служба передачи • Файловая система стандартного журналирования • Отчёты об ошибках • Планировщик классов мультимедиа • Теневая копия • Планировщик задач • Беспроводная настройка

Active Directory • Службы развёртывания • Служба репликации файлов • DNS • Домены • Перенаправление папок • Hyper-V • IIS • Media Services • MSMQ • Защита доступа к сети (NAP) • Службы печати для UNIX • Удалённое разностное сжатие • Службы удаленной установки • Служба управления правами • Перемещаемые профили пользователей • SharePoint • Диспетчер системных ресурсов • Удаленный рабочий стол • WSUS • Групповая политика • Координатор распределённых транзакций

Доступ к данным с помощью ADO.NET

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

До недавнего времени процессор баз данных Borland Database Engine поддерживал практически все виды доступа к данным, реализованные в средствах быстрой разработки приложений (RAD) компании Borland. Начиная с Delphi 3, были добавлены дополнительные механизмы доступа к данным, включая технологии ClientDataSet и DataSnap (ранее известная, как MIDAS). Что касается Delphi 7, то этот продукт обладает встроенной поддержкой не менее 6 различных механизмов доступа к данным, не считая решений сторонних фирм. Среди них одним из самых современных является технология ADO.NET, поддержку которой компания Borland реализовала в своих последних средствах разработки для .NET, включающих C# Builder и компилятор Delphi для .NET.

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

Читая статьи из предлагаемой серии, следует иметь в виду следующее. Во-первых, представленные статьи и сопутствующий код основаны на компиляторе для Delphi 7, чья обновленная версия 3 доступна с весны 2003 года. На момент написания данной статьи компания Borland еще не обладала интегрированной средой разработки для Delphi в среде .NET. Следовательно, рассмотренные в качестве примеров проекты не были созданы с помощью средств визуальной разработки. Вместо этого все визуальные компоненты (в случае, когда проект к ним обращается) были созданы и сконфигурированы, используя только программный код.

Во вторых, разработчики компании Borland возможно еще не закончили реализацию ADO.NET с помощью специальных методов, описанных в предлагаемой серии. Вероятнее всего компания Borland предоставит нечто вроде интерфейса ClientDataSet для .NET, который значительно упростит использование данных в управляемых устройствах, точно так же, как класс ADODataSet из библиотеки VCL упрощает использование ADO-объектов. Однако, если Borland разработает .NET ClientDataSet при использовании подхода, подобного своим классам ADODataSet, тогда, скорее всего, появится возможность использования как интерфейса ClientDataSet, так и более низкоуровневых методов, описанных в данной серии.

ADO.NET: Хранение данных и доступ к ним

ADO.NET – это название звена данных, предоставляемого библиотекой Foundation Class Library (FCL) в среде .NET. Концептуально технология ADO.NET может быть разделена на две различные составляющие: механизм доступа к данным и система хранения данных.

Все основные классы, интерфейсы и типы, используемые в ADO.NET, определены в пространстве имен второго уровня System.Data. Классы, соответствующие системе хранения данных, являются самостоятельными классами, которые можно использовать в любом приложении ADO.NET. Такие классы включают в себя DataColumn, DataRelation, DataRow, DataSet и DataTable, из которых наиболее важным является класс DataSet.

В отличие от механизма хранения, который определен в терминах классов, механизм доступа к данным определен на языке интерфейсов. Эти интерфейсы реализованы специальными классами, связанными с конкретным механизмом доступа к данным. В среде .Net Framework версии 1.1 существует пять механизмов доступа к данным. Они связаны со следующими пространствами имен третьего уровня: System.Data.SqlClient, System.Data.OleDb, System.Data.Odbc, System.Data.SqlServerCE и System.Data.OracleClient.

Например, рассмотрим класс SqlDataAdapter из пространства имен System.Data.SqlClient. Этот класс, который иногда относят к разряду DataAdapter, используется для загрузки данных в класс DataSet. SqlDataAdapter, подобно всем другим классам из разряда DataAdapter, реализует интерфейс IDbDataAdapter. Другие реализующие IDbDataAdapter классы включают в себя OleDbDataAdapter, OdbcDataAdapter и OracleDataAdapter.

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

Интерфейсы доступа к данным в ADO.NET

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

Такой реализованный в терминах интерфейсов доступ к данным в среде .NET имеет большое значение, поскольку он обеспечивает доступ к данным на уровне API, оставляя реализующим классам специфические детали. В среде .NET Framework 1.1 каждый из этих интерфейсов реализуется некоторым классом, который принадлежит одному из пространств имен, соответствующих конкретному механизму доступа к данным. Например, для доступа к данным с помощью сервера SQL можно использовать классы SqlConnection, SqlCommand, SqlDataReader и SqlDataAdapters. С другой стороны, при доступе к данным через провайдера OleDb следует, соответственно, использовать классы OleDbConnection, OleDbCommand, OleDbDataReader и OleDbDataAdapter.

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

IDbConnection

Классы, реализующие интерфейс IDbConnection, используются для установления соединения с источником данных. В большинстве случаев источником будет служить база данных, соответствующая конкретному серверу баз данных. Однако, благодаря поддержке соединений OleDB и ODBC, можно подсоединяться к любому источнику данных, для которого имеются провайдер OleDb и ODBC-драйвера. Например, к таким источникам относятся базы данных Paradox, dBase и MS Access.

Остальные классы, которые реализуют остальные перечисленные на диаграмме интерфейсы, основаны на соединении, поддерживаемом классом реализации интерфейса IDbConnection. Тем не менее, при использовании класса DataSet, который не заносит свои данные в основную БД (например, когда DataSet получает данные из XML-файла), нет необходимости использовать класс, реализующий интерфейс IDbConnection.

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

Интерфейс IDbConnection определяет свойства, которые подобны тем, что предоставляются компонентом SQLConnection ADO-методов dbExpress и ADOConnection или компонентом TSession процессора баз данных BDE.

IDbCommand

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

В рамках интерфейса IDbCommand запросы могут содержать параметры. Если это так, то следует связать данные с индивидуальными параметрами, используя класс, реализующий интерфейс IDbDataParameter. Все параметры, связанные с классом реализации интерфейса IDbCommand, находятся в свойстве Parameters соответствующего класса реализации. Это свойство является примером класса, реализующего интерфейс IDataParameterCollection.

Классы реализации интерфейса IDbCommand сходны с компонентом ADOCommand библиотеки VCL.

IdataReader

Классы, реализующие интерфейс IDataReader, обеспечивают быстрый, однонаправленный курсор к конечному набору данных, возвращаемому по запросу IDbCommand. Такие классы используются для выполнения операций, не требующих кэширования данных. Например, к таким операциям относится ситуация, когда не нужно загружать данные в класс DataTable или при итеративном обращении к конечному набору данных и выполнении условных вычислений над каждой встречающейся записью. Классы реализации интерфейса IDataReader схожи с классом SQLDataSet метода dbExpress.

IDbDataAdapter

Классы, реализующие интерфейс IDbDataAdapter, применяются для чтения данных и последующей их загрузки в класс DataSet. Для доступа к данным такие классы должны указывать на соответствующий класс реализации IDbConnection. Помимо загрузки данных в DataSet интерфейс IDbDataAdapters определяет запросы, используемые для работы с основной базой данных по извлечению и занесению информации. Реализующие интерфейс IDbDataAdapter объекты имеют много схожих черт с классом DataSetProvider в Delphi.

Классы реализации интерфейса IDbDataAdapter требуют наличия, по крайней мере, одного SQL-оператора, а во многих случаях не менее четырех. Как минимум, такие классы требуют SQL-оператора SELECT для идентификации записи, предназначенной для загрузки. Если данные, к которым осуществляют доступ классы реализации IDbDataAdapter, могут быть изменены, внесены или удалены, то должны присутствовать соответствующие SQL-операторы, которые предписывают, как эти данные обновляются, вставляются или удаляются.

SQL-операторы, применяемые в интерфейсе IDbDataAdapter, связаны со свойствами SelelectCommand, InsertCommand, UpdateCommand и DeleteCommand средства реализации IDbDataAdapter. Эти команды являются примерами классов, реализующих интерфейс IDbCommand. Все классы реализации интерфейса IDbDataAdapter могут принимать SQL-оператор SELECT в качестве параметра, по крайней мере, одного из своих перегруженных конструкторов. Если один из этих конструкторов используется для создания экземпляра IDbDataAdapter, то нет необходимости явно присваивать класс реализации IDbCommand свойству SelectCommand.

Вместо явного присваивания SQL-операторов свойствам InsertCommand, UpdateCommand и DeleteCommand можно использовать подходящие классы компоновки команд для генерации соответствующих SQL-команд. Тому примерами служат классы SQLCommandBuilder и OleDbCommandBuilder.

Дополнительная информация

За дополнительной информацией обращайтесь в компанию Interface Ltd.

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