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

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

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

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

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

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

Данная лабораторная работа основана на мне-е-е и Большом Биле!

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

Вставку, удаление можно делать построчно командами SQL на уровне БД. Редактирование тоже можно делать построчно, блокируя выбранные записи открытым соединением. Тогда проверка ограничений будет выполняться на уровне БД и мы вынуждены будем обрабатывать исключения самой БД.

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

Упражнение 1. Получение метаданных из БД

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

Чтобы сделать описание более кратким (и облегчить жизнь тем, кому скучно), будем стараться избегать этапа визуального проектирования, а все действия по формированию пользовательского интерфейса выполним в коде. В таком случае мне останется только привести отлаженный листинг и конечный снимок окна результата (а вам - лихо, 'по-программистски', скопировать, запустить и повеселиться...).

  • Создайте новое решение с именем ADO и добавьте в него новый проект с именем WinForms1
  • Заполните файл WinForms1.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;
    
namespace WinForms1
{
    public partial class Form1 : Form
    {
        // Объявили поля-ссылки для видимости в методах
        TabControl tabControl;
        DataTable schemaTable;
        ComboBox cbCollections, cbTables;
        DataGridView dataGridView1, dataGridView2;
    
        // Конструктор формы
        public Form1()
        {
            InitializeComponent();
            this.Text = "Упражнение 1. Извлечение метаданных";
            this.WindowState = FormWindowState.Maximized;
    
            CreateControl();// Динамически создать пользовательский интерфейс
            // Загрузить списки во вкладках
            LoadCollections();
            LoadTables();
        }
    
        // Имя метода пересекается с наследуемым (для разнообразия)
        new void CreateControl()
        {
            // Динамическое создание элементов управления
            tabControl = new TabControl();
            this.Controls.Add(tabControl);
            tabControl.Dock = DockStyle.Fill;
            TabPage page1 = new TabPage("Коллекции");
            tabControl.TabPages.Add(page1);// Добавили вкладку
            TabPage page2 = new TabPage("Таблицы");
            //tabControl.TabPages.Add(page2);// Добавили вкладку
            page2.Parent = tabControl;// Добавили вкладку (равноценно!!!)
    
            // Для динамического выравнивания элементов на первой вкладке
            TableLayoutPanel layoutPanel1 = new TableLayoutPanel();
            page1.Controls.Add(layoutPanel1);// Добавили панель к вкладке
            layoutPanel1.Dock = DockStyle.Fill;
    
            // Для динамического выравнивания элементов на второй вкладке
            TableLayoutPanel layoutPanel2 = new TableLayoutPanel();
            page2.Controls.Add(layoutPanel2);// Добавили панель к вкладке
            layoutPanel2.Dock = DockStyle.Fill;
    
            cbCollections = new ComboBox();
            cbCollections.Dock = DockStyle.Fill;
            layoutPanel1.Controls.Add(cbCollections);// Добавили список к панели
            // Зарегистрировали обработчик для первого списка
            cbCollections.SelectedIndexChanged += cbCollections_SelectedIndexChanged;
    
            // Объект отображения данных
            dataGridView1 = new DataGridView();// Создаем
            layoutPanel1.Controls.Add(dataGridView1);// Добавили сетку к панели
            dataGridView1.Dock = DockStyle.Fill;
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
    
            cbTables = new ComboBox();
            cbTables.Dock = DockStyle.Fill;
            layoutPanel2.Controls.Add(cbTables);// Добавили список к панели
            // Зарегистрировали обработчик для второго списка
            cbTables.SelectedIndexChanged += cbTables_SelectedIndexChanged;
    
            // Объект отображения данных
            dataGridView2 = new DataGridView();// Создаем
            layoutPanel2.Controls.Add(dataGridView2);// Добавили сетку к панели
            dataGridView2.Dock = DockStyle.Fill;
            dataGridView2.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
        }
    
        // Строка соединения к БД с абсолютным путем, определяемым сборкой
        String ConnectionString()
        {
            // Используем построитель строки подключения 
            OleDbConnectionStringBuilder objConnectionStringBuilder =
                new OleDbConnectionStringBuilder();
            objConnectionStringBuilder.Provider = "Microsoft.Jet.OLEDB.4.0";
            objConnectionStringBuilder.DataSource =
                Application.StartupPath.ToString() + @"\Data\Northwind.mdb";
    
            return objConnectionStringBuilder.ToString();
        }
    
        // Извлекаем в список имена всех коллекций БД
        void LoadCollections()
        {
            using (OleDbConnection connection = new
                     OleDbConnection(ConnectionString()))
            {
                connection.Open();
                schemaTable = connection.GetSchema();
            }
    
            foreach (DataRow row in schemaTable.Rows)
            {
                Object col = row["CollectionName"].ToString();
                cbCollections.Items.Add(col);
            }
    
            // Несвязанный список, можно сортировать
            cbCollections.Sorted = true;
            cbCollections.SelectedIndex = 0;
        }
    
        // Заполняем список именами таблиц БД
        void LoadTables()
        {
            // Создали, заполнили, скопировали в список и потеряли
            DataTable table = new DataTable();// Локальная ссылка на объект
    
            // Соединение закрывается после выхода из инструкции using
            using (OleDbConnection connection = new
                       OleDbConnection(ConnectionString()))
            {
                connection.Open();
                // Выбираем коллекцию только для таблиц
                table = connection.GetOleDbSchemaTable(
                    OleDbSchemaGuid.Tables,
                    new object[] { null, null, null, "TABLE" });
            }
    
            // Значения столбца TABLE_NAME скопировали в ComboBox
            foreach (DataRow row in table.Rows)
            {
                Object col = row["TABLE_NAME"].ToString();
                cbTables.Items.Add(col);
            }
    
            // Несвязанный список, можно сортировать
            cbTables.Sorted = true;
            cbTables.SelectedIndex = 0;// Установили список в начало
        }
    
        // Извлекаем информацию о выделенной коллекции
        void cbCollections_SelectedIndexChanged(object sender, EventArgs e)
        {
            schemaTable.Clear();// Очистим от предыдущего
            using (OleDbConnection connection = new
                       OleDbConnection(ConnectionString()))
            {
                connection.Open();
                schemaTable = connection.GetSchema(cbCollections.SelectedItem.ToString());
            }
            // Связываем таблицу и элемент отображения
            dataGridView1.DataSource = schemaTable;
        }
    
        // Извлекаем информацию о выделенной таблице
        void cbTables_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Все ссылки стековые
            String selectCommand = "";
            String tableName = cbTables.SelectedItem.ToString();
            if (tableName.IndexOf(' ') != -1)// Для таблицы 'Order Details'
                selectCommand = "SELECT * FROM " + "[" + tableName + "]";
            else
                selectCommand = "SELECT * FROM " + tableName;
            OleDbConnection connection = new OleDbConnection(ConnectionString());
            OleDbCommand objCommand = new OleDbCommand(selectCommand, connection);
    
            using (connection)// Заключаем в блок автоматического закрытия соединения при аварии
            {
                connection.Open();
                // Выполняем объект DbCommand одним из его методов
                OleDbDataReader dataReader = objCommand.ExecuteReader();
                // Извлечь метаданные таблицы и сразу привязать для показа
                dataGridView2.DataSource = dataReader.GetSchemaTable();
                connection.Close();
            }
        }
    }
}
  • Разберите код и запустите приложение

Метаданные, составляющие описание всей БД, мы извлекаем через объект соединения. Метод GetSchemaTable() объекта OleDbDataReader возвращает метаданные о каждом из столбцов в таблице.

Обратите внимание, что мы применили в качестве контейнеров элементов отображения два класса: TabControl и TableLayoutPanel. Класс TabControl изолирует в отдельных вкладках только интерфейс пользователя, но не изолирует код этих вкладок - все объекты, составляющие вкладки, должны иметь уникальные имена в рамках всего объекта TabControl. Класс TableLayoutPanel обеспечивает динамическое размещение в невидымых ячейках таблицы, наподобие таблицы HTML. Естественно, каждый контейнер имеет свои настройки, но мы воспользовались только настройками по умолчанию.

Очень полезен следующий снимок экрана, показывающий принятые в Access типы данных и их соответствие типам .NET. Большинство данных в БД хранятся в символьном виде и занимают ровно столько места, сколько требуется для хранения типа, например, Int16=2^16=256*256=65536 (пять знакомест), Int32=2^32=65536*65536=4294967296 (десять знакомест), DateTime=Год_месяц_день (в символьном представлении цифр занимает 8 знакомест). Тип DateTime называется так потому, что в одних колонках этого типа можно хранить дату, а в других - время.


Естественно, что типы данных в C# и типы данных в БД несовместимы. Одни называют объектными типами (типы уровня приложения), другие - реляционными типами (типы уровня БД). Однако функции API инфраструктуры ADO.NET автоматически преобразовывают их один в другой как при загрузке данных в приложение, так и при отправке их обратно в БД. Говорят, что поставщики ADO.NET отображают реляционные типы на объектные и наоборот. Здесь есть своя специфика, которую нужно учитывать при проектировании более изощренных приложений. В менее тонких случаях все происходит автоматически.

Тип данных LongBinary еще называют типом BLOB (Binary Large Object - большой объект двоичных данных), а тип LongText - CLOB (Character Large Object - большой объект символьных данных). В SQL Server такие типы носят имя IMAGE и TEXT соответственно. Для обработки больших типов данных, которые могут не поместиться целиком в оперативной памяти, могут применяться специальные приемы, связанные с потоковым доступом к данным и использованием дисковой памяти.

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

Вот и все, а дальше код еще одной вкладки для этого упражнения ...!!!

  • Добавьте к проекту WinForms1 новый пустой файл (шаблон Code File) с именем Form1Ext.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;
    
namespace WinForms1
{
    partial class Form1
    {
        // Объявили поля-ссылки для видимости в методах
        ComboBox cbTables1;
        DataGridView dataGridView;
    
        // Создаем вкладку и ее элементы
        void CreateControl1()
        {
            // Динамическое создание элементов управления
            TabPage page = new TabPage("Данные");
            tabControl.TabPages.Add(page);// Добавили вкладку
    
            // Для динамического выравнивания элементов
            TableLayoutPanel layoutPanel = new TableLayoutPanel();
            page.Controls.Add(layoutPanel);// Добавили панель к вкладке
            layoutPanel.Dock = DockStyle.Fill;
    
            cbTables1 = new ComboBox();
            cbTables1.Dock = DockStyle.Fill;
            layoutPanel.Controls.Add(cbTables1);// Добавили список к панели
            // Зарегистрировали обработчик для списка
            cbTables1.SelectedIndexChanged += cbTables1_SelectedIndexChanged;
    
            // Объект отображения данных
            dataGridView = new DataGridView();// Создаем
            layoutPanel.Controls.Add(dataGridView);// Добавили сетку к панели
            dataGridView.Dock = DockStyle.Fill;
            dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
        }
    
        // Заполняем список именами таблиц БД
        void LoadTables1()
        {
            // Создали, заполнили, скопировали в список и потеряли
            DataTable table = new DataTable();// Локальная ссылка на объект
    
            // Соединение закрывается после выхода из инструкции using
            using (OleDbConnection connection = new
                       OleDbConnection(ConnectionString()))
            {
                connection.Open();
                // Выбираем коллекцию только для таблиц
                table = connection.GetOleDbSchemaTable(
                    OleDbSchemaGuid.Tables,
                    new object[] { null, null, null, "TABLE" });
            }
    
            // Значения столбца TABLE_NAME скопировали в ComboBox
            foreach (DataRow row in table.Rows)
            {
                Object tableName = row["TABLE_NAME"].ToString();
                cbTables1.Items.Add(tableName);
            }
    
            // Несвязанный список, можно сортировать
            cbTables1.Sorted = true;
            cbTables1.SelectedIndex = 0;// Установили список в начало
        }
    
        // Извлекаем все данные выделенной таблицы
        void cbTables1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Все ссылки стековые
            String selectCommand = "";
            String tableName = cbTables1.SelectedItem.ToString();
            if (tableName.IndexOf(' ') != -1)// Для таблицы 'Order Details'
                selectCommand = "SELECT * FROM " + "[" + tableName + "]";
            else
                selectCommand = "SELECT * FROM " + tableName;
            OleDbConnection connection = new OleDbConnection(ConnectionString());
            OleDbCommand objCommand = new OleDbCommand(selectCommand, connection);
            OleDbDataAdapter adapter = new OleDbDataAdapter(objCommand);
            DataTable dataTable=new DataTable();
            adapter.Fill(dataTable);
            dataGridView.DataSource = dataTable;
        }
    }
}
  • Дополните конструктор класса Form1 вызовом методов из файла Form1Ext.cs
// Конструктор формы
        public Form1()
        {
            InitializeComponent();
            this.Text = "Упражнение 1. Извлечение метаданных";
            this.WindowState = FormWindowState.Maximized;
    
            CreateControl();// Динамически создать пользовательский интерфейс
            // Загрузить списки во вкладках
            LoadCollections();
            LoadTables();
    
            CreateControl1();// Динамически создать пользовательский интерфейс
            // Загрузить список в новой вкладке
            LoadTables1();
        }
  • Запустите приложение - теперь в новой вкладке мы можем просматривать содержимое выбранной из БД таблицы


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

При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл.

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

Юрий Макушин
Юрий Макушин
Россия, Москва, РЭА им. Плеханова, 2004