Практическое занятие № 9

Тема: Работа с базами данных

Цель работы: получить практические навыки по созданию программ для работы с БД

 

Ход работы

 

Пусть в СУБД Access спроектирована база данных (скачать). База защищена паролем "rpo" и имеет две таблицы.

 

Таблица "students", состоит из полей:

 

Имя поля

Тип

Размер

id_stud

Счетчик

Ключевое

fam

Текстовый

15

imya

Текстовый

15

otch

Текстовый

15

finance

Текстовый

10 (Госзаказ, Контракт)

datar

Дата/время

 

srbal

Числовой

Одинарной точности с плавающей точкой. Значение по умолчанию - 0

foto

Поле OLE

 
id_grup Числовой Внешний ключ для связи с таблицей groups

 

Таблица "groups", состоит из полей:

 

Имя поля

Тип

Размер

id_grup Счетчик Ключевое

grupa

Текстовый

30

 

В программе на C# выполните подключение базы данных

 

Указания: на панели "Источники данных" щелкните на кнопке "Добавить новый источник данных" (если панель не отображается, то выбери команду меню "Данные - Показать источники данных"). Запуститься мастер создания подключения к БД. В окне выберите значение "База данных", затем значение "Набор данных". На следующем шаге щелкните на кнопке "Создать подключение". В новом окне Вам будет предложено подключить файлы БД SQL Server. Щелкните на кнопке "Изменить" и выберите формат БД "Microsoft Access". После этого укажите нужный файл БД (путь к файлу не удаляйте, среда C# самостоятельно скопирует указанный файл в папку проекта и скорректирует путь к нему). Так как база защищена паролем, то щелкните на кнопке "Дополнительно" и в строке "Jet OLEDB: DataBase Password" укажите пароль "rpo". Для проверки соединения щелкните на кнопке "Проверить подключение". После задания всех параметров мастер предложит выбрать способ сохранения пароля к БД: не включать в строку подключения или включать в строку подключения. Выберите первый вариант для безопасности.

После задания параметров БД при переходе на следующий шаг мастера появится запрос на копирование файла БД в папку с проектом, подтвердите эту операцию.

На следующем шаге мастер предложит сохранить строку подключения в файл конфигурации приложения. Так как пароль доступа не включен в строку подключения, то можете согласиться на сохранение в файл.

На следующем шаге выберите обе таблицы students и groups, с которыми планируете работать в проекте, и щелкните "Готово".

Сразу нужно настроить поведение полей-счетчиков в таблицах. В окне "Источники данных" щелкните на кнопке "Изменить набор данных в конструкторе". Отобразится структура таблиц. Выделите поле id_stud в таблице students и измените свойства: AutoIncrementSeed = 1, AutoIncrementStep = 1. Выделите поле id_grup в таблице groups и измените свойства: AutoIncrementSeed = 1, AutoIncrementStep = 1.

 

Настройка корректного удаления новых записей

Если добавить новую запись в таблицу и сразу попытаться ее удалить, то часто появляется сообщение об ошибке, связанное с тем, что мастер подключения БД неправильно формирует команды на добавление, обновление и удаление данных. Для решения этой проблемы в окне со структурой таблиц щелкните правой кнопкой на строке "studentsTableAdapter" таблицы students, выберите команду "Настроить". В новом окне щелкните на кнопке "Дополнительно", в следующем окне выключите флажок "Использовать оптимистическую блокировку", щелкните ОК и Готово.

Повторите эти действия для таблицы groups.

 

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

 

 

Сетка заблокирована для ввода.

 

Указания: для подключения таблицы students нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу students. На форме появятся дополнительные компоненты для работы с таблицей: bazaDataSet - для доступа к подключению, studentsBindingSource - для работы с набором данных, studentsTableAdapter - для работы с копией таблицы БД. Для сетки задайте свойства: AutoSizeColumnsMode=Fill (ширина колонок подстраивается под размер сетки),  AllowUserToAddRows = false (запрет добавления новых строк в сетке), ReadOnly=true.

Для подключения таблицы groups нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу groups. На форме появятся дополнительные компоненты для работы с таблицей: groupsBindingSource - для работы с набором данных, groupsTableAdapter - для работы с копией таблицы БД. Так как таблица groups не будет отображаться в сетке, а будет использоваться для выпадающего списка, то сетку удалите.

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

Для формы откройте событие Load. В этом событии будут находится две команды Fill(), загружающие копии таблиц в компоненты TableAdapter. Над этими командами добавьте команду подстановки пароля в строку соединения:

 

Properties.Settings.Default["BazaConnectionString"] += ";Jet OLEDB:Database Password=rpo";

 

Добавьте в сетку поле Стипендия, которое вычисляется по формуле:

 

если финансирование равно "Госзаказ" и средний балл от 10..12  = 600;

если финансирование равно "Госзаказ" и средний балл 7..9 = 550

в остальных случаях 0.

 

Указания: для расчета будем пользоваться функцией вида:

 

iif(условие, значение при выполнение условия, значение при невыполнении условия)

 

В панели "Источники данных" щелкните на кнопке "Изменить набор данных в конструкторе".

В результате вы увидите структуры таблиц, входящих в подключение. В контекстном меню таблицы "students" выберите команду "Добавить - Столбец". Введите имя поля "stip" и в свойстве Expression введите формулу для расчета:

 

iif(finance='Госзаказ', iif(srbal=5,1450,iif(srbal>=4,1300,0)),0)

 

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

 

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

 

Указания: для настройки параметров сетки откройте ее свойство Columns. Вы увидите список всех ее колонок. Для каждой колонки в свойстве HeaderText укажите название, в свойстве Visible можно скрыть ненужные колонки. Для сетки задайте свойство ReadOnly=true. Для работы нашего кода далее обязательно назовите поле со средним баллом - "Ср.балл"

 

Слева под сеткой разместите надпись Label для отображения номера текущей записи и общего числа записей.

 

Указания: разместите слева под сеткой компонент label1. При переходе по записям  в сетке информация в этом компоненте должна изменяться. Для этого в событии CurrentChanged компонента studentsBindingSource введите код:

 

private void studentsBindingSource_CurrentChanged(object sender, EventArgs e)

{

    label1.Text = (studentsBindingSource.Position + 1).ToString() + " из " + studentsBindingSource.Count.ToString();

}

 

На форме разместите две кнопки для добавления и удаления данных.

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

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

 

Указания: добавьте в проект новую форму Form2. Выключите на форме кнопку закрытия окна. Для этого задайте свойство ControlBox = false.

 

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

 

public int pos=0;

 

Для кнопки "Добавить" на главной форме напишите код вида:

 

void Button1_Click(object sender, EventArgs e)
    {

    //запоминаем текущее положение в таблице

    pos = studentsBindingSource.Position;

    //добавляем новую запись

    studentsBindingSource.AddNew();

    //создаем экземпляр страничной формы

    Form2 form2 = new Form2();

    //открываем форму в модальном режиме

    form2.ShowDialog();

}

 

Для кнопки Удалить напишем код:

 

void Button2_Click(object sender, EventArgs e)

{

    //выдаем сообщение на подтверждение операции

    if (MessageBox.Show("Удалить строку?",

                        "Подтвердите операцию",

                        MessageBoxButtons.YesNo,

                        MessageBoxIcon.Question,

                        MessageBoxDefaultButton.Button2)==DialogResult.Yes)

    {

        //если пользователь подтвердил операцию

        //удаляем текущую строку

        studentsBindingSource.RemoveCurrent();

        //сохраняем изменения в БД

        studentsTableAdapter.Update(bazaDataSet.students);

    }

}

 

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

 

private void dataGridView1_DoubleClick(object sender, EventArgs e)

{

    //запоминаем текущее положение в таблице

    pos = studentsBindingSource.Position;

    //создаем экземпляр страничной формы

    Form2 form2 = new Form2();

    //открываем форму в модальном режиме

    form2.ShowDialog();

}

 

Вспомогательная страничная форма имеет вид:

 

 

Фото сотрудника заполняется с помощью диалога выбора графического файла при щелчке на кнопке "+". Кнопка "-" очищает поле Фото.

Поле Группа заполняется с помощью выпадающего списка, формируемого на основе второй таблицы-справочника "groups".

Поле Финансирование заполняется с помощью выпадающего списка из двух значений (Госзаказ, Контракт).

Поле Дата рождения заполняется с помощью выпадающего календаря.

Кнопка Сохранить закрывает окно и сохраняет запись.

Кнопка Отменить закрывает окно и отменяет внесенные изменения.

 

Указания: разместите на второй форме 4 текстовых поля TextBox (фамилия, имя, отчество, средний балл) , 2 выпадающих списка ComboBox (финансирование и группа), календарь DateTimePicker (дата рождения). Для фото добавьте компонент PictureBox (задайте свойство SizeMode = Zoom) и две кнопки для добавления и очистки фото.

 

Фото будем заполнять с помощью диалога. Нанесите на форму компонент OpenFileDialog и в свойстве Filter укажите допустимые форматы графических файлов:

 

Графические файлы|*.jpg;*.jpeg;*.gif;*.bmp;*.png

 

Для кнопки "+" напишите код добавления фотографии:

 

void Button1_Click(object sender, EventArgs e)

{

    //если файл в диалоге выбран

    if (openFileDialog1.ShowDialog()==DialogResult.OK)

    {

        //записываем файл в переменную

        Bitmap pict = new Bitmap(openFileDialog1.FileName);

        //в поле pictureBox отображаем переменную

        pictureBox1.Image = (Image)pict;

    }

}

 

Для кнопки "-" напишем код очистки фотографии:

 

void Button2_Click(object sender, EventArgs e)

{

    pictureBox1.Image=null;

}

 

Список Финансирование имеет два значения: Госзаказ, Контракт. Введите их через свойства Items списка.

 

Для поля Средний балл зададим ограничения от 3 до 5. При этом поле не может быть пустым и в поле можно вводить только числа. Что поле можно было пропустить, в нем нужно ввести 0.

Для поля textBox4 в событии Validating введем код:

 

private void textBox4_Validating(object sender, CancelEventArgs e)

{

    //переменная для вызова метода TryParse

    double rez;

 

    //если поле равно 0, то код проверки не выполняется   

    if (textBox4.Text == "0") return;

   

    //если содержимое поля не удалось конвертировать в double

    //значит в поле не число

    if (!double.TryParse(textBox4.Text,out rez))

    {

        //выдаем сообщение об ошибке       

        MessageBox.Show("Введенные данные не являются числом",

                        "Ошибка ввода",

                         MessageBoxButtons.OK,

                         MessageBoxIcon.Error);

        //отменяем ввод  

        e.Cancel=true;

        //завершаем код проверки

        return;

    }

 

    //если содержимое поля не попадает в диапазон от 3 до 5

    if (Convert.ToDouble(textBox4.Text) < 3 || Convert.ToDouble(textBox4.Text) > 5)

    {

        //выдаем сообщение об ошибке

        MessageBox.Show("Балл должен быть в диапазоне от 3 до 5",

                        "Ошибка ввода",

                         MessageBoxButtons.OK,

                         MessageBoxIcon.Error);

        //отменяем ввод

        e.Cancel = true;

    }

}

 

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

Откройте файл проекта Program.cs.

После строки заголовка класса проекта

 

static class Program

 

опишите глобальную переменную для доступа к главной форме в проекте

 

public static Form1 form1;

 

Замените команду

 

Application.Run(new Form1());

 

на команды

 

Program.form1 = new Form1();

Application.Run(form1);

 

После этого к главной форме проекта можно обратиться по имени Program.form1

 

Свяжем все компоненты на страничной форме Form2 с полями таблицы через компонент studentsBindingSource на главной форме (его имя будет Program.form1.studentsBindingSource). Сначала сделайте этот компонент видим для других форм. Для этого задайте свойство Modifiers = Public.

Поле справочник для ввода названия группы будет заполнять данными через компонент grousBindingSource (полное имя Program.form1.groupsBindingSource)Сделайте этот компонент также видимым для других форм (Modifiers = Public).

 

В событии Load страничной формы добавим код:

 

void Form2_Load(object sender, EventArgs e)

{

    //поле textBox1 привязывается к полю fam   

    textBox1.DataBindings.Add(new Binding("Text", Program.form1.studentsBindingSource, "fam", true));

    //поле textBox2 привязывается к полю imya

    textBox2.DataBindings.Add(new Binding("Text", Program.form1.studentsBindingSource, "imya", true));

    //поле textBox3 привязывается к полю otch

    textBox3.DataBindings.Add(new Binding("Text", Program.form1.studentsBindingSource, "otch", true));

    //список comboBox1 привязывается к полю finance

    //так как список содержит фиксированный набор данных,

    //то привязываем свойство списка Text

    comboBox1.DataBindings.Add(new Binding("Text", Program.form1.studentsBindingSource, "finance", true));

    //календарь dateTimePicker1 привязывается к полю datar

    dateTimePicker1.DataBindings.Add(new Binding("Value", Program.form1.studentsBindingSource, "datar", true));

    //поле textBox4.Text привязывается к полю srbal  

    textBox4.DataBindings.Add(new Binding("Text", Program.form1.studentsBindingSource, "srbal", true));

   

    //список comboBox2 привязывается к полю id_grup

    //так как список содержит набор данных из другой таблицы,

    //то привязываем свойство списка SelectedValue

    comboBox2.DataBindings.Add(new Binding("SelectedValue", Program.form1.studentsBindingSource, "id_grup", true));

    //при этом значения для списка берутся из набора данных groupsBindingSource

    //задаем параметры списка-справочника

    //источник данных для списка   

    comboBox2.DataSource=Program.form1.groupsBindingSource;

    //в списке отображаются названия групп  

    comboBox2.DataMember="grupa";

    //после выбора в основную таблицу записывается номер группы

    comboBox2.ValueMember="id_grup";

   

    //компонент pictureBox1.Image привязывается к полю photo  

    pictureBox1.DataBindings.Add(new Binding("Image", Program.form1.studentsBindingSource, "foto", true));

}

 

Для сохранения или отмены мы будем обращаться к компонентам studentsTableAdapter и bazaDataSet на главной форме. Поэтому их нужно сделать "видимыми". Задайте для них свойство Modifiers = true.

 

Для кнопки Сохранить страничной формы напишем код:

 

void Button1_Click(object sender, EventArgs e)

{

    //проверяем все поля на правильность ввода

    Program.form1.Validate();

    //завершаем редактирование текущей записи   

    Program.form1.bindingSource1.EndEdit();

    //обновляем данные в БД

    //при этом компоненты доступа к БД находятся на главной форме

    Program.form1.studentsTableAdapter.Update(Program.form1.bazaDataSet.students);

    //закрываем форму

    Close();

}

 

Для кнопки Отменить напишем код:

 

void Button2_Click(object sender, EventArgs e)

{

    //отменяем редактирование текущей записи

    Program.form1.bindingSource1.CancelEdit();

    //закрываем форму

    Close();

    //возвращаем курсор на предыдущую позицию в таблице

    Program.form1.bindingSource1.Position=Program.form1.pos; 

}

 

Справа от выпадающего списка "Группа" разместите кнопку для редактирования таблицы-справочника с помощью формы вида:

 

 

Указания: на форме Form1 для работы с таблицей-справочником сделайте видимым для других форм компонент groupsTableAdapter (Modifiers = Public).

На форме Form2 для кнопки справа от списка "Группа" введите код вида:

 

private void button5_Click(object sender, EventArgs e)

{

    Form3 form3 = new Form3();

    form3.ShowDialog();

}

 

Добавьте в проект новую форму Form3. Для формы задайте свойства: FormBorderSyle = FixedDialog, MaximizeBox = false, MinimizeBox = false, StartPosition = CenterScreen.

Список групп будет показывать в виде сетки. Нанесите на форму компонент DataRowView. Для сетки задайте свойство AutoSizeColumnsMode=Fill (ширина колонок подстраивается под размер сетки).

 

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

 

private void Form3_Load(object sender, EventArgs e)

{

    dataGridView1.DataSource = Program.form1.groupsBindingSource;

    //скрываем первую колонку с полем-счетчиком

    dataGridView1.Columns[0].Visible = false;

    //переименовываем колонку с названием групп

    dataGridView1.Columns[1].HeaderText = "Группа";

}

 

При закрытии формы сохраняем изменения в таблице-справочнике. В событии FormClosed напишем код:

 

private void Form3_FormClosed(object sender, FormClosedEventArgs e)

{

    //если изменения в таблице есть

    if (Program.form1.bazaDataSet.groups.GetChanges() != null)

        //сохраняем их в БД

        Program.form1.groupsTableAdapter.Update(Program.form1.bazaDataSet.groups);

}