Опубликован: 05.08.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 5:

Просмотр данных OLE DB средствами ADO.NET

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

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

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

  1. Уровень "Хранилище данных" (Data Store) - место, где находятся сами данные. Это может быть реляционная база данных, XML-файл, текстовый файл или какая-то другая структурированная система хранения .
  2. Уровень "Доступ к данным" (Data Access Layer - DAL) - код, который необходим для извлечения и манипулирования необработанными данными, находящимися в хранилище.
  3. Уровень "Бизнес-логика" (Business Logic Layer - BLL) - код, который берет извлеченные данные и предоставляет их клиенту в более понятном виде, а также обеспечивает безопасность и согласованность действий клиента и данных.
  4. Уровень "Представление" ("Пользовательский интерфейс") (Presentation/User Interface Layer - UI) - код, который определяет, что именно должен видеть пользователь на экране, включая форматирование данных и навигационное меню системы.

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

  • DbConnection - используется для установки соединения с источником данных
  • DbCommand - используется для выполнения SQL-команд и хранимых процедур
  • DbDataReader - модуль чтения, который предоставляет быстрый последовательный доступ к данным только для чтения. Он сам автоматически не управляет открытием и закрытием соединения и это нужно делать вручную, открывая как можно позже и закрывая как можно раньше
  • DbDataAdapter - выполняет две задачи:
    1. Наполнение набора данных DataSet (автономная коллекция таблиц и отношений) информацией, извлеченной из источника данных
    2. Применение изменений данных, выполненных пользователем в DataSet, к источнику данных

Этот обобщенный поставщик напрямую не применяется, а наследуется специализированными поставщиками, имена которых имеют префиксы Odbc, OleDb, Sql, Oracle. Мы будем использовать набор классов OleDb для файловой БД Northwind.mdb. Нужно четко понимать, что поставщики ADO.NET отображают реляционную модель данных хранилища в объектно-ориентированную модель приложения. Это значит, что данные таблицы или множества таблиц после их считывания приложением представляются наборами взаимосвязанных объектов соответствующих типов и дальнейшая работа проводится уже с этими объектами.

Объект DbCommand может выполнять три типа команд, определяемых перечислением CommandType:

  1. Text - команда будет выполнять прямой SQL-оператор, который мы укажем в свойстве DbCommand.CommandText
  2. StoredProcedure - команда будет выполнять созданную нами ранее процедуру, хранимую в источнике данных. Свойство DbCommand.CommandText представляет имя хранимой процедуры
  3. TableDirect - команда извлечет все записи указанной в свойстве DbCommand.CommandText таблицы подключенной БД (не работает с поставщиком SQL Server)

Для выполнения созданного и настроенного объекта DbCommand он имеет три команды:

  1. ExecuteReader() - выполняет запрос SELECT и возвращает объект DbDataReader, который является оболочкой однонаправленного курсора, доступного только для чтения
  2. ExecuteScalar() - выполняет запрос SELECT и возвращает значение первого поля первой строки из набора строк, сгенерированного командой. Этот метод обычно применяется при исполнении агрегатной команды SELECT, использующей функции наподобие COUNT() или SUM() для вычисления единственного значения
  3. ExecuteNonQuery() - для выполнения незапросной команды, которая не требует выборки данных с помощью SQL-оператора SELECT. Применяется для исполнения SQL-команд вставки, удаления или обновления записей. Возвращаемое значение означает количество строк, обработанное командой

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

Некоторые методы DbDataReader
Метод Описание
bool Read() Перемещает курсор строки результирующего набора на следующую строку. Этот метод должен быть вызван, также, перед чтением первой строки данных, т.к. после наполнения DbDataReader данными курсор устанавливается перед первой строкой. Метод возвращает true, если есть куда переводить, при применении к последней строке он вернет false
object GetValue(int ordinal) Возвращает значение поля текущей строки с указанным индексом столбца. Тип возвращенного значения заменяется типом .NET, наиболее подходящим типу столбца в хранилище
int GetValues(object[ ] values) Заполняет массив values полями текущей записи. Количество полей определяется размером массива, который можно определить по свойству FieldCount
int GetInt32(int ordinal) Эти методы возвращают значение поля с указанным индексом в текущей строке (нумерайия полей начинается с нуля). Тип поля определяет имя метода
char GetChar(int ordinal)
bool GetBoolean(int ordinal)
System.DateTime GetDateTime(int ordinal)
bool NextResult() Переводит курсор перед первой строкой следующего набора результатов, если было прочитано несколько наборов составной SQL-командой SELECT
void Close() Закрывает модуль чтения

Упражнение 1. Просмотр таблицы с помощью объектов DbCommand и DbDataReader

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

  • Создайте командой File/New/Project новое решение с именем ADO и проект WinForms1 для первого упражнения

  • Поместите на форму из панели Toolbox нужные компоненты и настройте их в соответствии с таблицей свойств
Компонент Свойство Значение
Form Text Упражнение 1
DataGridView (Name) myDataGrid
  Dock Top
  AutoSizeColumnsMode Fill
Button (Name) btnPopulate
  Text Заполнить
  AutoSize true
Button (Name) btnDataBind
  Text Связать
  AutoSize true
Label (Name) lblRegCount
  Text Количество записей таблицы:
  • В панели Solution Explorer создайте папку Data для корневого узла проекта командой Add/New Folder, вызовите для нее контекстное меню и скопируйте из прилагаемой папки Source файл Northwind.mdb командой Add/Existing Item. При появлении мастера Data Source Configuration Wizard отмените его кнопкой Cancel
  • Выделите в Solution Explorer файл Northwind.mdb и в панели Properties проверьте, что его свойства имеют значение
    • Build Action=Content
    • Copy to Output Directory=Copy always
  • Создайте обработчик для кнопки btnPopulate и btnDataBind
  • Внесите изменения в файл Form1.cs, выделенные в листинге
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
    
// Дополнительные пространства имен
using System.Data.OleDb;
using System.Data.Common;
using System.Collections;
    
namespace WinForms1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
    
            // Отключаем кнопку 'Связать'
            btnDataBind.Enabled = false;
            // Отключить системную кнопку
            this.MaximizeBox = false;
        }
    
        // Создаем объект массива списков
        ArrayList dbRecordsList = new ArrayList();// Поле
    
        // Строка соединения с абсолютным путем к БД, определяемым сборкой
        String ConnectionString(String fileName)
        {
            string JetEngineString = @"Provider=Microsoft.Jet.OLEDB.4.0;"
                + "Jet OLEDB:Engine Type=5;Data Source=";
            string pathToFile = Application.StartupPath.ToString() + "\\Data\\";
            return JetEngineString + pathToFile + fileName.Trim() + ".mdb";
        }
    
        // Заполнение массива списков данными 
        private void btnPopulate_Click(object sender, EventArgs e)
        {
            // Создаем объект соединения
            OleDbConnection objConnection = 
                new OleDbConnection(ConnectionString("Northwind"));
    
            dbRecordsList.Clear();// Очищаем список (необязательно!)
    
            // После выполнения тела инструкции using освободится подключение
            using (objConnection)
            {
                // Создаем объект команды с последующими настройками
                OleDbCommand objCommand = new OleDbCommand();
                objCommand.CommandType = CommandType.Text;// Не обязательно, по умолчанию
                objCommand.CommandText = "SELECT * FROM Customers";
                objCommand.Connection = objConnection;
    
                // Или сразу одним конструктором
                //OleDbCommand objCommand = new OleDbCommand("SELECT * FROM Customers", objConnection);
    
                objConnection.Open();// Открываем соединение
    
                // Выполняем объект DbCommand одним из его методов
                OleDbDataReader dataReader = 
                    objCommand.ExecuteReader(           // Заполнить набор данных
                    CommandBehavior.CloseConnection);   // Отработать и сразу закрыть соединение
    
                // Счетчик количества записей
                int recCount = 0;
                if (dataReader.HasRows)// Флаг поднят, если есть строки 
                {
                    // Перебрать все строки набора и добавить в коллекцию списка
                    foreach (DbDataRecord rec in dataReader)
                    {
                        dbRecordsList.Add(rec);
                        recCount++;// Не будем использовать, подсчитаем ниже командой
                    }
                }
    
                // Подсчитываем число записей в таблице
                objCommand = new OleDbCommand("SELECT COUNT(*) FROM Customers", objConnection);
                objConnection.Open();
                recCount = (int)objCommand.ExecuteScalar();
                objConnection.Close();
                lblRegCount.Text += recCount.ToString();
            }
    
            // Переключаем доступность кнопок
            btnPopulate.Enabled = false;
            btnDataBind.Enabled = true;
        }
    
        private void btnDataBind_Click(object sender, EventArgs e)
        {
            // Связываем список с элементом отображения
            myDataGrid.DataSource = dbRecordsList;
    
            btnDataBind.Enabled = false;// Отключаем кнопку
        }
    }
}
  • Запустите приложение, чтобы получить результат

DbDataReader, возвращаемый методом objCommand.ExecuteReader(), позволяет читать данные в соответствии с исполняемой командой SELECT построчно в однонаправленном, доступном только для чтения потоке. Применение DbDataReader - простейший путь извлечения данных из хранилища, но ему недостает возможностей сортировки и связывания автономного DataSet.

DbDataReader не позволяет выполнять обратный просмотр набора результатов и редактировать их. Это лишь способ последовательного чтения в одном направлении, использующий постоянное подключение к БД. В соответствии со значением перечисления CommandBehavior.CloseConnection соединение с БД закрывается сразу же, как только объект команд закончит чтение данных в DbDataReader. Но для подстраховки в нашем приложении модуль чтения и подключение закрываются автоматически после завершения инструкции using.

В отключенном режиме загруженные данные находятся в объекте ArrayList и показываются пользователю после связывания с DataGridView. Объект DataGridView, в нашем случае, показывает данные в режиме только для чтения, поскольку 'знает', что ArrayList не является редактируемым.

Алексей Бабушкин
Алексей Бабушкин

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

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000