Visual studio как добавить ado net
Первый шаг при разработке программы для работы с базами данных – это создание самой базы. Выберите в меню Вид \ Другие окна \ Обозреватель серверов, в появившемся окне нажмите правой кнопкой мыши по «Подключения данных» и выберите «Создать новую базу данных SQL Server».
В качестве имени сервера введите (LocalDB)\v11.0.
MSSQL поддерживает 2 типа авторизации: по имени пользователя Windows, или по своему собственному списку пользователей. При использовании авторизации SQL Server Authentication необходимо ввести имя пользователя и пароль. Выберите «Использовать аутентификацию Windows» и укажите имя для новой базы данных.
Если не возникнет ошибок подключения или авторизации, то будет создана новая БД, и в окне Обозреватель серверов в разделе Подключения данных появится новая ветка с именем базы. Если ее раскрыть, то появятся записи для работы с этой базой.
Для примера создадим БД мобильных телефонов. Для хранения данных в базе используются таблицы, поэтому начнем с них. Разработка структуры будущей базы является важным этапом при создании приложений работы с данными, так четкая структура и наличие логических связей между таблицами упрощает приложение, и наоборот – лишние поля в таблицах, дублирование полей, недостаточные связи и т.п. могут существенно осложнить работу.
Сначала определим, какую информацию мы будем хранить о телефонах. В нашем случае, например, для упрощения будем учитывать 6 характеристик: производитель, модель, год выпуска, цвет, вес, изображение телефона. Если просто создать таблицу с заданными полями, то мы сможем хранить всю интересующую информацию, но это будет не оптимальное решение.
Все поля в общем случае будут иметь уникальное значение от телефона к телефону, за исключением производителя и года выпуска. Год можно кодировать целым числом типа int, поэтому данное поле не критично, но вот название производителя будет повторяться часто, тем более оно является строковым параметром, и его хранение в одной таблице с моделями телефонов нецелесообразно, так как попросту приведет к дублированию строк. А теперь представим, что производитель сменил свое наименование, а у нас в таблице уже содержатся тысячи моделей данной фирмы, которые потребуется все переименовывать!
Для решения проблемы лучше будет хранить имена производителей в отдельной таблице, а в таблице моделей просто указывать его номер. Тогда для смены названия фирмы просто понадобится сменить имя в таблице производителей у одной записи, и все, ее номер не поменяется, и таблицу моделей редактировать не придется. К тому же когда нам понадобится вывести все модели телефонов заданной фирмы, поиск будет осуществляться по номеру, т.е. сравнением целых чисел, что намного быстрее, нежели сравнение строк в первом случае.
Еще одним приемом при проектировании БД, позволяющим упростить и ускорить работу с базой, является наличие уникального номера-идентификатора в таблицах (ключа), однозначно определяющего строку таблицы. Гораздо удобнее и быстрее обращаться к записи в таблице в виде «номер 231», чем «фирма Nokia, модель …, год …, цвет …, вес …, …».
Начнем с создания таблицы производителей. Если раскрыть ветку с созданной базой данных в дереве в окне Обозреватель серверов, то появятся записи Таблицы, Представления, Типы и другие объекты базы. Нажмите правой кнопкой по Таблицы и выберите Добавить новую таблицу. Появится окно ввода имени полей таблицы, их типов и «Допустимы значения Nulls» (может ли поле не содержать значения, т.е. быть пустым). Создайте следующие поля: ID - тип int и Name - тип nvarchar(20).
Поле ID – уникальный числовой идентификатор типа int. Чтобы сервер MSSQL сам назначал номера при добавлении новых записей в таблицу, в свойствах поля в списке выберите Спецификация идентификатора и установите значения True для (Идентификатор).
Поле Name – название фирмы, nvarchar(20) означает строка длиной до 20 символов.
Измените имя таблицы на Firms и нажмите кнопку «Обновить».
Теперь создайте еще одну таблицу Models для моделей телефонов с полями:
Имя поля Тип
ID int
ID_Firm int
model nvarchar(20)
year int
color nvarchar(15)
weight int
photo image
Названия полей говорят сами за себя, поле ID_Firm будет содержать номер фирмы, т.е. значения из поля ID в таблице Firms.
Вы всегда можете поменять структуру таблицы, нажав правой кнопкой по ее имени в окне Обозреватель серверов и выбрав Открыть определение таблицы.
Вызовите таким образом на редактирование таблицу Firms, нажмите правой кнопкой на поле Индексы, и в появившемся меню выберите «Добавить новый индекс». В свойствах созданного индекса установите параметр Уникальный в значение True. В параметре Столбцы выберите поле ID. Нажмите правой кнопкой мыши на поле ID таблицы, и в появившемся меню выберите «Задать первичный ключ». Т.е. поле ID теперь является уникальным ключом (идентификатором) для записей в таблице. Обновите базу данных.
Теперь отредактируем таблицу Models, по аналогии нажмите правой кнопкой на пункте «Внешние ключи», и в появившемся меню выберите «Добавить новый внешний ключ». Внешние ключи позволяют задавать связи между таблицами, в нашем случае надо сообщить серверу, что поле ID_Firm связано с полем ID из таблицы Firms.
Обновите базу данных.
Теперь можно занести данные в таблицу. Нажмите правой кнопкой по имени таблицы, выберите меню Показать таблицу данных.
Для таблицы Firms:
Для таблицы Models:
Теперь, когда БД готова, можно приступать к написанию программы. Создайте проект Windows Forms, поместите на форму компонент SplitContainer. На его левую панель поместите DataGridView (поменяйте имя на dgvFirms, выравнивание Dock на Fill). На правую панель поместите компонент Panel c выравниваем по низу Dock = Bottom, на эту панель поместите 3 кнопки «Добавить», «Редактировать», «Удалить» с именами btnModelAdd, btnModelEdit и btnModelDel.
На оставшееся место в правой панели SplitContainer добавьте еще один компонент DataGridView с именем dgvModels и выравниваем Fill:
Чтобы появились заголовки в компонентах DataGridView (далее будем называть просто грид) как показано на рисунке, нажмите сначала правой кнопкой мыши на левом гриде, и выберите Правка столбцов:
Данный грид будет содержать имена фирм, поэтому добавьте в него 2 столбца с именами (св-во Name) colFirmID и colFirmName. Header text это то, что будет отображаться в заголовке столбца в самом гриде, поэтому желательно занести соответствующие русские названия. Столбец colFirmID будет хранить идентификатор записи и отображаться не будет, поэтому установите у него свойство Visible в false.
Теперь создадим столбцы для правого грида, который будет содержать модели телефонов:
Имена для столбцов соответственно: colModelID, colModelName, colModelYear, colModelColor, colModelWeight, colModelPhoto. Последний столбец будет отображать фото телефона, поэтому поменяйте его тип на DataGridViewImageColumn. Первый столбец будет содержать идентификатор ID моделей, поэтому сделайте его невидимым Visible = false.
Установите у обоих гридов свойства AllowUserToAddRows = false, AllowUserTDeleteRows = false и ReadOnly = true, что отключит непосредственное редактирование в гридах (мы будем пользовать отдельные кнопки). SelectionMode = FullRowSelect и ColumnHeadersHeightSizeMode = AutoSize, AutoSizeColumnsMode = Fill чтобы выбирать курсором строки целиком и растягивать столбцы по ширине грида соответственно.
Отдельно у правого грида dgvModels установите AutoSizeRowsMode = AllCellsExceptHeaders, чтобы высота строк в нем растягивалась по высоте изображения телефона.
Всего компонент DataGridView содержит более 200 свойств и событий для настройки отображения данных, начиная со смены цвета фона ячеек до их ручной прорисовки с помощью библиотеки GDI+ и т.п., но это выходит за рамки нашей статьи.
Все классы для работы с MSSQL находятся в соответствующем пространстве имен, поэтому добавьте к остальным директивам using в начале файла:
Запустите программу и проверьте на наличие ошибок.
Как уже можно было догадаться из проделанных действий, в левой части окна программы будет находиться перечень фирм-производителей телефонов, в правой модели телефонов для выбранной фирмы, кнопки внизу будут осуществлять манипуляцию данными.
Добавьте внутрь класса формы переменные:
Переменная Con будет хранить соединение к базе данных, объекты класса DataTable используются для данных таблиц, булева переменная-флаг UpdateFirms пригодится позже, переменная id_firm – идентификатор текущей выбранной фирмы.
Добавьте в конструктор формы код (отмечен жирным шрифтом):
При создании соединения с БД используется строка соединения (Connection String), содержащая параметры подключения: имя сервера, базы, логин, пароль и др. Ее можно посмотреть, если нажать правой кнопкой в окне Обозреватель серверов на соединении с БД в ветке Подключения данных и выбрать Свойства. Хранение строки непосредственно в коде программы не лучшее решение, так как при смене настроек сервера БД, программу придется перекомпилировать, поэтому чаще ее хранят во внешних конфигурационных файлах.
Конструкция try .. catch используется для перехвата ошибок при исполнении программы. Если в коде, расположенном в блоке try <> произойдет ошибка (исключение Exception), то управление будет немедленно передано в блок catch <>. Исключение является классом, тип класса определяет вид произошедшей ошибки (в нашем случае ошибка класса SqlException), и объект данного класса будет помещен в переменную e для дальнейшей обработки программой.
Так как операция подключения к серверу зависит от многих факторов и далеко не всегда будет успешной (нет сервера, не найден, нет базы, неверный логин и т.п.), то целесообразно проверять этот этап на ошибки. Далее в коде программы перехват ошибок встретится еще не раз.
После подключения создаются таблицы для данных, они назначаются гридам на форме в качестве источников для отображения информации, и идет присоединение столбцов к именам столбцов таблиц в БД. Свойство грида AutoGenerateColumns определяет, будет ли грид сам создавать столбцы. Так как мы их уже создали сами, то отключаем.
Добавьте в класс формы 2 функции:
Событие возникает, когда происходит перемещение курсора по фирмам, при этом нам необходимо получить ID выбранной фирмы (CurrentRow – выбранная строка в гриде, Cells[0] – первый столбец, содержащий идентификаторы), и обновить список моделей телефонов. Если при получении ID фирмы возникнет ошибка, то id_firm = -1 и ф-ция RefreshModels обновлять список не будет.
Осталось заполнить гриды фирмами и моделями при первом запуске программы, для этого воспользуемся событием Shown формы:
private: System::Void Form1_Shown(System::Object^ sender, System::EventArgs^ e)
Запустите программу, попробуйте выбирать разные фирмы для смены моделей. Фактически мы добились просмотра нашей БД сотовых телефонов, пора приступать к редактированию, для чего уже заранее были созданы 3 кнопки в нижней части окна.
Код для кнопки «Добавить»:
С помощью sql запроса insert добавляется новая запись в таблицу моделей с идентификатором текущей выбранной фирмы. Так как sql команда insert (как и все последующие) не возвращает данные в программу, то используется метод ExecuteNonQuery(). После добавления обновляем список моделей, чтобы изменения отразились в гриде.
Код для кнопки «Удалить»:
Через них будет передавать в эту форму из главной объект SqlConnection чтобы иметь возможность выполнять sql команды, и грид моделей чтобы заполнить поля формы информацией о модели. Переменная id для хранения идентификатора модели.
Чтобы при появлении формы на экране в полях уже содержалась информация, создадим событие Shown:
Получение текстовой информации о цвете, модели и др. не представляет труда, они хранятся в столбцах грида по порядку. С полем фото сложнее, так как оно представляет собой двоичную информацию, т.е. массив байт. Вдобавок к этому, объект Image в PictureBox может считывать информацию из файла, потока, или другого такого же объекта, но не из массива. Поэтому чтобы представить массив байт в виде изображения, приходится предварительно записывать его в MemoryStream – поток, хранящий данные в памяти.
Код для кнопки «Загрузить»:
Ничего особенного нет, занесение имени выбранного изображения в PictureBox. Код для кнопки «Сохранить»:
Сохранение информации начинается с текстовых полей. Используется sql команда update, но стоит отметить, что, несмотря на то, что год и вес являются числами, внутри запроса их значения все равно помещаются внутри одиночных кавычек ‘’. Если бы их не было, то в случае, например, если после редактирования значение года выпуска окажется пустым, в sql запросе будет year= что вызовет ошибку на сервере. С кавычками же year=’’, сервер сам выполняет преобразование типов, и пустая строка будет расценена как 0, и ошибки не возникнет.
К сожалению, сохранить подобным образом изображение не получится, так как представить в виде строки массив байт длиной в десятки, сотни килобайт или больше, достаточно сложно. Для таких случаем в классе SqlCommand предусмотрены «параметры» - именованные переменные, начинающиеся в sql запросе с символа @, значения которых можно задавать практически любым способом, включая и просто двоичные массивы. Для получения массива байт изображения из файла используется файловый поток FileStream.
В конце функции закрываем окно с помощью DialogResult, значение OK сообщит основному окну программы, что запись была изменена, и надо обновить грид моделей.
Теперь, когда форма редактирования готова, можно вернуться к основному окну, и добавить код для последней оставшейся кнопки:
Запустите программу и проверьте на наличие ошибок. Теперь можно редактировать модели, загружать фото телефонов в базу, понажимать на заголовки столбцов в гриде для сортировки (встроенная возможность DataGridView). Можно и дальше дорабатывать программу, расширяя ее функциональность, например:
- Редактирование фирм – можно сделать аналогично моделям
- Поиск – при заполнении гридов запросом select добавить в строку запроса условия where для заданных критериев поиска
- Добавить проверку вводимых данных для исключения ошибок
- Печать отчетов
- Экспорт данных
- И многое другое…
Генерация файла *.edmx
На консоль выводится список опций, которые можно указывать утилите для генерации необходимых файлов, основываясь на существующей базе данных; кроме того, доступны опции для генерации совершенно новой базы данных на основе имеющихся сущностных файлов. Ниже описаны некоторые общие опции EdmGen.exe:
/mode:FullGeneration
Генерировать файлы *.ssdl, *.msl, *.csdl и клиентские сущности из указанной базы данных
/project:
Базовое имя, которое должно использоваться для сгенерированного кода и файлов. Обычно это имя базы данных, из которой извлекается информация (допускается сокращенная форма — /р:)
/connectionstring:
Строка соединения, используемая для взаимодействия с базой данных (допускается сокращенная форма — /с:)
/language:
/pluralize
Позволяет автоматически выбирать множественное или единственное число для имени набора сущностей, имени типа сущности и имени навигационного свойства, согласно правилам английского языка
Как и платформа .NET 4.0 в целом, программная модель EF поддерживает программирование в стиле сначала домен, что позволяет создавать свойства (с применением типичных объектно-ориентированных приемов) и использовать их для генерации новой базы данных. В этом вводном обзоре ADO.NET EF ни подход "сначала модель", ни генерация сущностной модели клиентской стороны с помощью утилиты EdmGen.exe применяться не будут. Вместо этого будут использоваться визуальные конструкторы EDM из среды Visual Studio 2010.
Щелчок на кнопке Add (Добавить) приводит к запуску мастера создания модели сущностных данных (Entity Data Model Wizard). На первом шаге мастер позволяет выбрать, нужно генерировать EDM из существующей базы данных либо определить пустую модель (для разработки в стиле "сначала модель"). Выберите опцию Generate from database (Генерировать из базы данных) и щелкните на кнопке Next (Далее).
На втором шаге мастера выбирается база данных. Если соединение с базой данных внутри проводника сервера Visual Studio 2010 уже существует, оно будет присутствовать в раскрывающемся списке. Если же нет, щелкните на кнопке New Connection (Создать соединение). В любом случае выберите базу данных AutoLot и отметьте флажок Save entity connection settings in App.config as (Сохранить настройки соединения в файле App.config как):
Прежде чем щелкать на кнопке Next, взгляните на формат строки соединения:
Основной интерес в ней представляет флаг metadata, который используется для указания имен встроенных данных XML-ресурсов концептуального, физического и файла отображений (вспомните, что во время компиляции файл *.edmx будет разделен на отдельные файлы, и данные этих файлов примут вид двоичных ресурсов, встраиваемых в сборку).
На последнем шаге мастера можно выбрать элементы из базы данных, для которой необходимо сгенерировать модель EDM. В рассматриваемом примере ограничимся только таблицей Inventory. Щелкните на кнопке Finish для генерации модели EDM.
Изменение формы сущностных данных
После завершения работы с мастером откроется визуальный конструктор EDM в IDE-среде с одной сущностью по имени Inventory. Просмотреть композицию любой сущности в визуальном конструкторе можно в окне Model Browser (Браузер моделей), которое открывается через пункт меню View --> Other Windows (Вид --> Другие окна).
Теперь взгляните на формат концептуальной модели для таблицы базы данных Inventory, представленный в папке Entity Types (Типы сущности). В узле хранилища, имя которого совпадает с именем базы данных (AutoLotModel.Store), находится физическая модель базы данных:
По умолчанию имена сущностей будут основаны на именах исходных объектов баз данных; однако, вспомните, что имена сущностей в концептуальной модели могут быть любыми. Чтобы изменить имя сущности либо имена свойств сущности, необходимо выбрать нужный элемент в визуальном конструкторе и установить соответствующим образом свойство Name в окне свойств (Properties). Переименуйте сущность Inventory в Car и свойство PetName в CarNickname:
Теперь выберите сущность Car в визуальном конструкторе и снова загляните в окно Properties. Вы должны увидеть поле Entity Set Name (Имя набора сущностей), также переименованное из Inventories в Cars. Значение Entity Set Name важно, потому что оно соответствует имени свойства в классе контекста данных, который используется для модификации базы данных. Вспомните, что это свойство инкапсулирует переменную-член ObjectSet<T> класса-наследника ObjectContext.
Прежде чем двигаться дальше, скомпилируйте приложение; это приведет к обновлению кодовой базы и генерации файлов *.csdl, *.msl и *.ssdl на основе данных файла *.edmx.
Просмотр отображений
Имея данные в измененной форме, можно просматривать отображения между концептуальным уровнем и физическим уровнем в окне Mapping Details (Сведения об отображениях), которое открывается через пункт меню View --> Other Windows --> Mapping Details. Взгляните на рисунок ниже и обратите внимание, что узлы в левой части дерева представляют имена данных из физического уровня, в то время как узлы справа представляют имена концептуальной модели:
Просмотр данных сгенерированного файла *.edmx
Теперь давайте посмотрим, что именно мастер EDM Wizard сгенерировал. Щелкните правой кнопкой мыши на файле InventoryEDM.edmx в проводнике решения и выберите в контекстном меню пункт Open With. (Открыть с помощью). В открывшемся диалоговом окне выберите опцию XML Editor (Редактор XML). Это позволит просмотреть XML-данные, лежащие в основе представления в визуальном конструкторе EDM. Структура этого XML-документа разделена на четыре части: все они находятся в корневом элементе <edms:Edmx>.
Подэлемент <edmx:Runtime> определяет XML-данные для концептуальной, физической и модели уровня отображения. Ниже показано определение физической таблицы базы данных Inventory:
Следующая важная часть файла *.edmx — элемент <edmx:ConceptualModels>. который определяет измененные сущности клиентской стороны. Как видно, сущность Cars определяет свойство CarNickname, которое изменяется в визуальном конструкторе:
Это перемещает на уровень отображения, который окно Mapping Details и исполняющая среда EF используют для подключения имен в концептуальной модели к физической модели:
Последней частью файла *.edmx является элемент <Designer>. который исполняющей средой EF не используется. Он содержит инструкции, используемые Visual Studio для отображения сущностей на поверхности визуального конструктора.
Удостоверьтесь, что проект скомпилирован, по крайней мере, однажды, и щелкните на кнопке Show All Files (Показать все файлы) в проводнике решений. Затем зайдите в папку obj\Debug, а после этого — в edmxResourcesToEmbed. Здесь находятся три XML-файла, основанные на содержимом файла *.edmx:
Firebird (InterBase) можно использовать для систем практически любого уровня, начиная от однопользовательских настольных приложений со встраиваемой базой данных (Embed Database), до клиент-серверных приложений уровня корпорации.
Средства и технологии, используемые в статье:
Что такое OLE DB Provider?
Более детальное описание технологии OLE DB дано в статье: ODBC Firebird драйвер, ODBC InterBase или OLE DB?
Для дальнейшей работы скачайте и установите IBProvider Professional Edition.
Методы подключения к Firebird и InterBase
Параметры строки подключения для работы с Firebird, InterBase
Для формирования строки подключения в Net 2.0 появился класс OleDbConnectionStringBuilder:
Существует определенный набор свойств инициализации IBProvider-a, который необходимо установить перед выполнением соединения с БД:
СОВЕТВсегда включайте в параметр Location имя сервера базы данных. Это позволит обеспечить совместимость со всем версиями Firebird .
Способы хранения строк подключения
В реальных приложениях никто не прописывает строки подключения к базе данных в коде. Гораздо эффективнее использовать для этой цели либо настройки приложения (технология Settings), либо отдельный файл подключения.
- Создайте пустой файл с расширением .udl
- Откройте файл (Enter), появится связанный с данным расширением диалог для настройки подключения:
- В списке OleDb провайдеров выберете IBProvider v3:
- Задайте параметры подключения по аналогии с рисунком и нажмите кнопку «Проверить подключение»:
- Нажмите «Ок» для записи информации о подключении в файл
Теперь для того чтобы использовать подключение, описанное udl файлом достаточно явно или через OleDbConnectionStringBuilder задать свойство File Name
В свойствах проекта выберите вкладку Settings и создайте новое свойство с именем ConnectionString и типом (Connection string):
ПРИМЕЧАНИЕЕсли нажать на кнопку “Data Links” появится уже знакомый нам диалог конфигурации Microsoft Data Link
Для того чтобы прочитать строку подключения из файла конфигурации необходимо создать экземпляр класса настроек вашего приложения:
Для облегчения написания примеров был создан класс ConnectionProvider, который инкапсулирует в себе все, описанные методы подключения.
Шифрование строки подключения. Data Protection API
Один из вариантов защитить строку подключения в своем конфигурационном файле это воспользоваться Data Protection API (DAPI) . Начиная с Windows 2000, DAPI является частью операционной системы.
Допустим, нам необходимо зашифровать данные, хранящиеся в секции connectionStrings. Для этого мы воспользуемся классом DataProtectionConfigurationProvider:
Добавим к проекту ссылку на System.Configuration.dll и используем следующий код:
ПРЕДУПРЕЖДЕНИЕДанных хранящиеся в секции могут быть расшифрованы только на том компьютере, на котором были зашифрованы. Таким образом, процедуру шифрования данных необходимо вызывать на компьютере конечного пользователя.
Данный пример как раз подходит для этих целей. При установке приложения мы помещаем в папку с программой ещё не зашифрованный App.Config. При первом запуске приложения данная процедура его зашифрует и, в последствии, программа будет работать уже с защищенной секцией. Можно так же вызывать процедуру шифрования во время установки приложения.
К сожалению, нет стандартных средств для защиты UDL файлов, поэтому стоит воспользоваться способом хранения защищенных строк подключения в файле конфигурации.
Команды
Команды предназначены для передачи запросов базе данных. Для Ole Db провайдеров команда реализуется классом OleDbCommand. Команда всегда выполняется для заданного открытого подключения к базе данных в контексте транзакции.
Для того чтобы выполнить запрос к базе данных необходимо выполнить следующую последовательность действий:
ExecuteScalar
ExecuteReader
Данный метод возвращает объект OleDbDataReader, которые по своему назначению очень близок объекту Recordset из классического ADO. Он использует однонаправленное ForwardOnly чтение данных, реализуя подсоединенную модель доступа. Таким образом, при его использовании необходимо наличие отрытого подключения к базе.
Навигация по строкам результирующего множества осуществляется при помощи метода Read(), который возвращает true , в случае если ещё остались строки и false в противном случае. При вызове метода команды ExecuteReader(), созданный им объект OleDbDataReader не спозиционирован на первой строке результирующего множества и для её прочтения необходимо сначала вызвать метод Read().
Наиболее удобным способом чтения данных из результирующего множества является использование метода Read() совместно с конструкцией while:
ПРИМЕЧАНИЕОбратите внимание что после вызова метода OleDbDataReader.Close(), подключение к базе данных будет закрыто. Это произошло потому, что я применил перегруженный метод ExecuteReader() с заданным параметром CommandBehavior.CloseConnection. По умолчанию после выполнения метода OleDbDataReader.Close() подключение к базе данных остается открытым.
ExecuteNonQuery
Метод применяется для выполнения запросов, которые возвращают количество обработанных записей, таких как insert, update, delete, а так же для выполнения хранимых процедур, результат которых помещается в OUT параметры команды:
Параметры команд
В большинстве случаев при выполнении команды требуется задать её параметры. Параметры добавляются в коллекцию Parameters. Они могут быть именованные и позиционные. Пример команды с позиционными параметрами:
Для того чтобы добавить параметр нужно воспользоваться:
- для добавления именованного параметра и значения метод AddWithValue()
- для добавления как именованных, так и неименованных параметров перегруженный метод Add()
Нельзя не сказать о существующих ограничениях при использовании именованных параметров совместно с OleDbCommand. В MSDN написано, что именованные параметры поддерживаются только для поставщиков данных MSSQL и Oracle, а для поставщиков данных Ole Db и ODBC поддерживаются только позиционные параметры. Использовать именованные параметры все же можно, но их добавление в коллекцию Parameters необходимо осуществлять в том же порядке, в каком они следуют в запросе. К примеру, если текст команды:
то сначала необходимо добавить параметр currency , а потом country:
Задавать значения параметров можно уже в произвольном порядке:
Существуют два способа обработки результатов хранимых процедур:
- хранимая процедура возвращает результирующее множество
- результат выполнения хранимой процедуры помещается в OUT параметры команды
Для первого способа используется обычная SQL-инструкция:
Результат её выполнения обрабатывается при помощи объекта OleDbDataReader:
Результат выполнения помещается в OUT параметры команды, которые предварительно необходимо создать:
В следующем примере хранимая процедура увеличивает значение генератора на единицу и возвращает полученное значение через OUT-параметр:
Доступ к массивам InterBase, Firebird
Следующий пример демонстрирует чтение и запись массива из 5 элементов:
Работа с BLOB полями в Firebird, InterBase
IBProvider поддерживает работу с двумя типами BLOB полей: содержащих текст и бинарные данные. Благодаря встроенному в IBProvider конвертеру типов, работа с BLOB полями происходит так же, как и с обычными типами данных:
СОВЕТВ примере OleDbDataReader использован совместно с конструкцией using . Он поддерживает интерфейс IDispose и после завершения работы сам позаботится о своем закрытии, а если в метод OleDbCommand.ExecuteReader() передать значение CommandBehavior.CloseConnection , то так же будет закрыто подключение к базе данных.
В качестве еще одного примера работы с BLOB полями в Firebird (InterBase), я хочу предложить вам, ставший уже классическим, пример записи рисунка в BLOB поле.
«There is already an open DataReader associated with this Connection which must be closed first.»
Предыдущий пример работы с BLOB полями как раз и показывает применение технологии MARS. В нем демонстрируется последовательное чтение данных и их одновременное их обновление.
Таким образом, применение MARS возможно не только для MS SQL Server , как пишут во многих источниках информации, но и для других баз данных.
Использование транзакций
Автоматическое управление транзакциями в IBProvider
Любая операция с базой данных должна выполняться в контексте транзакции. В своих примерах я постоянно использовал метод OleDbConnection.BeginTransaction(), так как предпочитаю всегда явно управлять транзакциями.
IBProvider может управлять транзакциями автоматически. Для конфигурирования этого режима существуют несколько свойств инициализации, которые могут быть заданы в строке подключения:
Следующий пример демонстрирует включение режима автоматического управления транзакциями с уровнем изоляции RepeatableRead:
Уровни изоляции транзакций в Firebird, InterBase
Уровень изоляции транзакции фактически задает область видимости данных между параллельно выполняющимися транзакциями.
IBProvider поддерживает три уровня изоляции транзакций: Read Committed, Repeatable Read и Snapshot.
Вложенные транзакции в Firebird, InterBase
TransactionScope и распределенные транзакции в Net 2.0
В Net Framework 2 появилось новое пространство имен System.Transaction, которое предоставляет поддержку распределенных транзакций. IBProvider поддерживает распределенные транзакции за счет расширения COM+ Microsoft Transaction Server (MTS). Распределенные транзакции позволяют нам преодолеть границы базы данных и выполнять действия с различными БД в контексте одной распределенной транзакции. Таким образом, гарантируется, что данные у всех участников распределенной транзакции будут согласованы.
Для организации распределенных транзакций служит объект TransactionsScope. В случае если он обнаружит, что его в контексте используется несколько подключений, он будет использовать распределенную транзакцию, иначе локальную. Следующий пример иллюстрирует поведение объекта TransactionsScope:
Управление транзакциями Firebird, InterBase через SQL
Использование именованных точек сохранения
IBProvider позволяет использовать именованные точки сохранения внутри транзакций. Для задания новой точки необходимо выполнить SQL запрос:
Для того чтобы откатить или зафиксировать транзакцию до определенной точки сохранения необходимо выполнить:
В следующем примере определяется одна точка сохранения между двумя командами:
Обработка ошибок в Visual Studio
- Код ошибки OleDb
- Коллекцию ошибок OleDbError
В примере умышленно пропущены обязательные параметры строки подключения User ID и Password. В результате выполнения данного кода будет сгенерировано Ole Db исключение. В коллекции ошибок будет содержаться два объекта OleDbError. На экран будет выведено следующее:
Событие InfoMessage
Решение было оформлено в виде компонента, который поставляется в виде исходных текстов вместе с примерами к статье. Он реализован в виде словаря OleDbProperties индексированного по названию свойства, в котором присуствует фабричный метод GetPropertiesFor():
Фабричный метод обращается к поставщикам свойств унаследованных от PropertyProviderBase. В компоненте реализовано три поставщика для объектов OleDbCommand, OleDbConnection и OleDbDataReader:
Каждый из поставщиков возвращает свой набор свойств, соответствующий группам Ole Db:
- Полный список свойств группы Data Source Information
- Список свойств группы Initialization (задаются в строке подключения к Firebird, InterBase.
- Свойства набора рядов группы Rowset
Пул подключений
Флаг | Знач. | OLE DB сервисы |
---|---|---|
DBPROPVAL_OS_ENABLEALL | -1 | Используются все сервисы |
DBPROPVAL_OS_RESOURCEPOOLING | 1 | Ресурсы должны помещаться в пул |
DBPROPVAL_OS_TXNENLISTMENT | 2 | При необходимости сессии должны быть автоматически подключены к глобальной транзакции |
DBPROPVAL_OS_AGR_AFTERSESSION | 8 | Поддержка операций за пределами сессии |
DBPROPVAL_OS_CLIENTCURSOR | 4 | Поддержка клиентских курсоров на уровне OLE DB Services, если их не поддерживает управляемый провайдер |
DBPROPVAL_OS_DISABLEALL | 0 | Все сервисы отключены |
В примерах к статье класс OleDbServicesValues содержит константы для всех этих флагов. Для комбинации флагов можно использовать операцию побитового исключения ( &
) констант невостребованных сервисов из константы DBPROPVAL_OS_ENABLEALL.
Следующий пример тестирует производительность при использовании различных Ole Db сервисов:
OleDbServicesValues.AggregationAfterSession (параметр “OLE DB Services = -13 ”).
Чуть медленнее будет работать при использовании всех Ole Db сервисов. И наконец производительность значительно падает (примерно в 20 раз) при полностью выключенных сервисах.
Отсоединенная модель. DataSet
Заполнение объекта DataSet
Класс DataSet служит для хранения данных, загруженных из базы, в памяти. Фактически он представляет собой набор таблиц связанных отношениями и в идеальном случае копирует структуру исходной базы данных.
Он позволяет существенно сократить количество обращений к базе данных. Это особенно критично для WEB-приложений, для которых частое подключение к базе данных не является оптимальным.
Существуют несколько способов заполнения объекта DataSet:
DataTableReader
Данный класс позволяет использовать объект DataTable в режиме однонаправленного ForwardOnly чтения. Он, так же как и OleDbDataReader наследуется от базового класса DBDataReader.
Этот способ чтения таблиц DataSet может быть полезен, когда используются общие методы для отсоединенного источника данных и данных, которые формируются в подсоединенном режиме (OleDbCommand.ExecuteReader()). К примеру, такая ситуация нередкость, когда операции работы с базой данных нужно вынести в веб-сервис. В таком случае, чтобы не переписывать большое количество кода, используещего OleDbDataRead, применяют DataTableReader к данным DataSet.
Следующий пример демонстрирует использование общего метода PrintDBDataReader() для подсоединенного и отсоединенного режимов работы:
Передача изменений обратно в базу данных
После того как в DataSet были внесены изменения, их необходимо передать обратно в базу. Для этого у объекта OleDbDataAdapter есть метод Update(). Прежде чем его использовать, необходимо настроить наш адаптер. В этом нам поможет класс OleDbCommandBuilder. Он позволяет сгенерировать команды для операций вставки, обновления и удаления, а так же создать соответствующую коллекцию параметров команд.
Ниже приведен пример передачи изменений из DataSet в базу данных:
- установить соединение с хранилищем данных;
- создать и заполнить данными объект DataSet ;
- отключиться от хранилища данных и вернуть изменения, внесенные в объект DataSet обратно в хранилище данных.
Объект DataSet - это тип данных , представляющий локальный набор таблиц и информацию об отношениях между ними.
DataSet - набор связанных таблиц. На практике можно создать на клиенте объект DataSet, который будет представлять полную копию удаленной базы данных .
После создания объекта DataSet и его заполнения данными можно программными средствами производить запросы к нему и перемещаться по таблицам, выполнять все операции , как при работе с обычными базами данных: добавлять в таблицы новые записи, удалять и изменять существующие, применять к ним фильтры и т.п. После того как клиент завершит внесение изменений, информация о них будет отправлена в хранилище данных для обработки.
Создание DataSet осуществляется при помощи управляемого провайдера ( managed provider ).
Управляемый провайдер - это набор классов, реализующих интерфейсы, определенные в пространстве имен System.Data.
Речь идет об интерфейсах IDbCommand , IDbDataAdapter , IDbConnection и IDataReader (рисунок 8.1).
увеличить изображение
Рис. 8.1. Взаимодействие клиента с управляемыми провайдерами
В состав ADO.NET включены два управляемых провайдера: провайдер SQL и провайдер OleDb. Провайдер SQL специально оптимизирован под взаимодействие с Microsoft SQL Server версии 7.0 и последующих. Для других источников данных предлагается использовать провайдер OleDb, который можно использовать для обращения к любым хранилищам данных, поддерживающим протокол OLE DB. Следует отметить, что провайдер OleDb работает при помощи "родного" OLE DB и требует возможности взаимодействия при помощи СОМ.
Типы пространства имен System.Data предназначены для представления данных, полученных из источника (но не для установления соединения непосредственно с источником).
В основном эти типы представляют собой объектные представления примитивов для работы с базами данных - таблицами, строками, столбцами, ограничениями и т. п. Наиболее часто используемые типы System.Data представлены в таблице 8.2.
При разработке прикладных систем в сети Интернет ( Web -приложения) необходимо добиваться максимальной масштабируемости. Система должна работать одинаково эффективно как с малым, так и с большим числом пользователей.
По этой причине, в ADO.NET используется модель работы пользователя в отрыве от источника данных. Приложения подключаются к базе данных только на небольшой промежуток времени. Соединение устанавливается только тогда, когда клиент удаленного компьютера запрашивает на сервере данные. После того, как сервер подготовил необходимый набор данных, сформировал и отправил их клиенту в виде WEB -страницы, связь приложения с сервером сразу же обрывается, и клиент просматривает полученную информацию уже не в связи с сервером. При работе в сети Интернет нет необходимости поддерживать постоянную "жизнеспособность" открытых соединений, поскольку неизвестно, будет ли конкретный клиент вообще далее взаимодействовать с источником данных. В таком случае целесообразнее сразу освобождать занимаемые серверные ресурсы, что обеспечит обслуживание большего количества пользователей. Модели доступа к данным представлена на рисунке 8.2.
Уровень данных. Это по сути дела базовый уровень, на котором располагаются сами данные (например, таблицы базы данных MS SQL Server ). На данном уровне обеспечивается физическое хранение информации на магнитных носителях и манипуляция с данными на уровне исходных таблиц ( выборка , сортировка , добавление, удаление, обновление и т. п.).
Уровень бизнес-логики. Это набор объектов, определяющих, с какой базой данных предстоит установить связь и какие действия необходимо будет выполнить с содержащейся в ней информацией. Для установления связи с базами данных используется объект DataConnection . Для хранения команд, выполняющих какие либо действия над данными, используется объект DataAdapter . И, наконец, если выполнялся процесс выборки информации из базы данных , для хранения результатов выборки используется объект DataSet . Объект DataSet представляет собой набор данных "вырезанных" из таблиц основного хранилища, который может быть передан любой программе-клиенту, способной либо отобразить эту информацию конечному пользователю, либо выполнить какие-либо манипуляции с полученными данными.
Обмен данными между приложениями и уровнем бизнес-логики происходит с использованием формата XML, а средой передачи данных служат либо локальная сеть ( Интранет ), либо глобальная сеть ( Интернет ).
Когда требуется получить набор строк из базы данных , необходимо выполнить следующую последовательность действий:
- открыть соединение ( connection ) с базой данных;
- вызвать на исполнение метод или команду, указав ей в качестве параметра текст SQL -запроса или имя хранимой процедуры;
- закрыть соединение с базой данных.
Связь с базой данных остается активной только на достаточно короткий срок - на период выполнения запроса или хранимой процедуры.
Когда команда вызывается на исполнение , она возвращает либо данные, либо код ошибки . Если в команде содержался SQL - запрос на выборку - SELECT , то команда может вернуть набор данных. Вы можете выбрать из базы данных только определенные строки и колонки, используя объект DataReader , который работает достаточно быстро, поскольку использует курсоры read-only, forward-only .
Если требуется выполнить более чем одну операцию с данными, например, получить некоторый набор данных, а затем скорректировать его, - то необходимо выполнить последовательность команд. Каждая команда выполняется отдельно, последовательно одна за другой. Между выполняемыми командами соединение с базой отсутствует. Например, чтобы получить данные из базы - открывается связь , выбираются данные, затем связь закрывается. Когда выполняется обновление базы после корректировки информации пользователем, снова открывается связь , выполняется обновление данных в исходных таблицах и связь снова закрывается.
Команды работы с данными могут содержать параметры, т. е. могут использоваться параметризированные запросы, как, например, следующий запрос :
Значения параметров могут задаваться динамически, во время выполнения приложения.
Как правило, в приложениях необходимо извлечь информацию из базы данных и выполнить с ней некоторые действия: показать пользователю на экране монитора, сделать нужные расчеты или послать данные в другой компонент . Очень часто, в приложении нужно обработать не одну запись , а их набор: список клиентов, перечень заказов, набор элементов заказа и т. п. Как правило, в приложениях требуется одновременная работа с более чем одной таблицей: клиенты и все их заказы; автор и все его книги, заказ и его элементы, т.е. с набором связанных данных. Причем для удобства пользователя данные требуется группировать и сортировать то по одному, то по другому признаку. При этом нерационально каждый раз возвращаться к исходной базе данных и заново считывать данные. Более практично работать с некой временной "вырезкой" информации, хранящейся в оперативной памяти компьютера.
Эту роль выполняет набор данных - DataSet , который представляет собой своеобразный кэш записей, извлеченных из базового источника. DataSet может состоять из одной или более таблиц, он имеет дело с копиями таблиц из базы данных источника. Кроме того, в данном объекте могут содержаться связи между таблицами и некоторые ограничения на выбираемые данные. Структура объекта DataSet приведена на рисунке 8.3.
Данные в DataSet - это некий уменьшенный вариант основной базы данных . Тем не менее, вы можете работать с такой "вырезкой" точно так же, как и с реальной базой. Поскольку каждый пользователь манипулирует с полученной порцией информации, оставаясь отсоединенными от основной базы данных , последняя может в это время решать другие задачи.
Конечно, практически в любой задаче обработки данных требуется корректировать информацию в базе данных (хотя и не так часто, как извлекать данные из нее). Вы можете выполнить операции коррекции непосредственно в DataSet , a потом все внесенные изменения будут переданы в основную базу данных.
Важно отметить то, что DataSet - пассивный контейнер для данных, который обеспечивает только их хранение. Что же нужно поместить в этот контейнер , определяется в другом объекте - адаптере данных DataAdapter . В адаптере данных содержатся одна или более команд, которые определяют, какую информацию нужно поместить в таблицы объекта DataSet , по каким правилам нужно синхронизировать информацию в конкретной таблице DataSet и соответствующей таблицей основной базы данных и т. п. Адаптер данных обычно содержит четыре команды SELECT, INSERT, UPDATE, DELETE , для выборки, добавления, корректировки и удаления записей.
Например, метод Fill объекта DataAdapter , заполняющего данными контейнер DataSet , может использовать в элементе SelectCommand следующий запрос :
Набор данных DataSet - "независимая" копия фрагмента базы данных , расположенная на компьютере пользователя. Причем в этой копии могут быть не отражены те изменения, которые могли внести в основную базу данных другие пользователи. Если требуется увидеть самые последние изменения, сделанные другими пользователями, то необходимо "освежить" DataSet , повторно вызвав метод Fill адаптера данных.
Читайте также: