Несвязный уровень взаимодействия ADO.NET
При работе на несвязном уровне ADO.NET по-прежнему нужно использовать объекты соединения и команды. Кроме того, необходимо использовать специальный объект, называемый адаптером данных (и расширяющий абстрактный DbDataAdapter), чтобы извлекать и обновлять данные.
Объект адаптера данных поставщика данных обрабатывает соединение с базой данных автоматически. С целью расширения возможностей масштабируемости адаптеры данных сохраняют соединение открытым минимально возможное время. Как только вызывающая сторона получает объект DataSet соединение с СУБД разрывается, и вызывающая сторона остается со своей локальной копией удаленных данных. В сущности, DataSet позволяет клиенту имитировать постоянно открытое соединение, в то время как реальные операции выполняются с наборами данных, находящимися в памяти.
В отличие от связного слоя, данные, полученные с помощью адаптера данных, не обрабатываются с помощью объекта чтения данных. Вместо этого для перемещения данных между вызывающей стороной и источником данных объекты адаптера данных (DataAdapter) используют объекты DataSet. Тип DataSet – это контейнер, используемый для любого числа объектов DataTable, каждый из которых содержит коллекцию объектов DataRow и DataColumn.
В рамках отсоединенной модели ADO.NET объект DataSet становится важным элементом технологии отсоединенного доступа. Объект-представитель DataSet представляет множество таблиц.
Для успешного решения задачи представления в DataSet есть все необходимое. Его функциональные возможности позволяют загрузить в локальное хранилище на стороне приложения данные из любого допустимого для ADO.NET источника: SQL Server, Microsoft Access, XML-файл.
В числе данных – членов этого класса имеется набор Tables. Объект DataSet может содержать таблицы, количество которых ограничивается лишь возможностями набора Tables.
Для каждой таблицы – элемента набора Tables может быть (и, естественно, должна быть) определена структура таблицы. В случае, когда приложение взаимодействует с реальной базой данных, структура таблиц в DataSet должна соответствовать структуре таблиц в базе данных. DataSet – это находящийся в памяти объект ADO.NET, используемый в приложении для представления данных; он определяет согласованную реляционную модель базы данных, которая не зависит от источника содержащихся в нем данных. Степень полноты модели определяется задачами, которые решает приложение.
Объект DataSet может представлять абсолютно точную модель базы данных, и в таком случае эта модель должна будет включать полный набор структурных элементов базы данных, включая таблицы, содержащие данные, с учетом установленных ограничений и отношений между таблицами.
Содержащуюся в объекте DataSet информацию можно изменять независимо от источника данных (от самой БД). Соответствующие значения формируются непосредственно в программе и добавляются в таблицы.
При работе с базой данных данные могут собираться из разных таблиц, локальное представление которых обеспечивается различными объектами – представителями классов DataSet. В классе DataSet определено множество перегруженных методов Merge, которые позволяют объединять содержимое нескольких объектов DataSet.
Любой объект-представитель класса DataSet позволяет организовать чтение и запись содержимого (теоретически – информации из базы) в файл или область памяти. При этом можно читать и сохранять:
- только содержимое объекта (собственно информацию из базы);
- только структуру объекта – представителя класса DataSet;
- полный образ DataSet (содержимое и структуру).
Таким образом, DataSet является основой для построения различных вариантов отсоединенных объектов – хранилищ информации.
Класс DataSet – класс и не абстрактный и не интерфейс. Это значит, что существует множество вариантов построения отсоединенных хранилищ.
На основе базового класса DataSet можно определять производные классы определенной конфигурации, которая соответствует структуре базы данных.
Можно также создать объект – представитель класса DataSet оригинальной конфигурации и добавить непосредственно к этому объекту все необходимые составляющие в виде таблиц (объектов – представителей класса Table) соответствующей структуры и множества отношений Relation.
Объект – представитель класса DataSet и сам по себе, без сопутствующего окружения, представляет определенную ценность. Дело в том, что информация, представляемая в приложении в виде таблиц, не обязательно должна иметь внешний источник в виде реальной базы данных. Ничто не мешает программисту обеспечить в приложении чтение обычного "плоского" файла или даже "накопить" необходимую информацию посредством интерактивного взаимодействия с пользователем, используя при этом обычный диалог. В конце концов, база данных – это один из возможных способов организации информации (а не только ее хранения!). Не случайно DataSet представляет отсоединенные данные.
База данных характеризуется множеством таблиц и множеством отношений между таблицами.
Объявление класса DataSet включает:
- набор (возможно, что пустой) объявлений классов DataTable (фактически это описание структуры таблиц, составляющих данный класс DataSet);
- набор объявлений классов DataRelations, который обеспечивает установку связей между разными таблицами в рамках данного DataSet.
Структура DataSet может в точности повторять структуру БД и содержать полный перечень таблиц и отношений, а может быть частичной копией БД и содержать, соответственно, лишь подмножество таблиц и подмножество отношений. Все определяется задачей, решаемой с помощью данного DataSet.
Объект – представитель данного класса DataSet обеспечивает представление в памяти компьютера фрагмента данной БД. Этот объект является локальным представлением (фрагмента) БД.
В свою очередь, в приложении, обеспечивающем взаимодействие с базой данных, объект DataSet функционирует исключительно за счет объекта DataAdapter, который обслуживает DataSet.
При этом DataAdapter является центральным компонентом архитектуры отсоединенного доступа.
Объект DataAdapter – составная часть провайдера данных. Это подсоединенная компонента объектной модели ADO.NET. Он обеспечивает связь между источником данных и объектом DataSet и используется для двух целей – заполнения объекта DataSet и модификации источника данных.
Функциональные возможности DataAdapter реализуются за счет метода Fill(), который изменяет данные в DataSet. При выполнении метода Fill() объект DataAdapter заполняет DataTable или DataSet данными, полученными из БД.
После обработки данных, загруженных в память, с помощью метода Update() можно записать модифицированные записи в БД. Метод Update() позволяет изменять данные в источнике данных с целью достижения обратного соответствия данных в источнике данных по отношению к данным в DataSet.
Фактически, DataAdapter управляет обменом данных и обновлением содержимого источника данных.
DataAdapter предоставляет набор команд для подключения к БД и модификации данных.
Достойны особого внимания четыре свойства этого класса, фактически представляющие команды БД. Через эти команды объект DataAdapter и воздействует на DataSet и БД.
1. SelectCommand – содержит текст (строку sql) или объект команды, осуществляющей выборку данных из БД. При вызове метода Fill() эта команда выполняется и заполняет объект DataTable или объект DataSet.
2. InsertCommand – содержит текст (строку sql) или объект команды, осуществляющий вставку строк в таблицу.
3. DeleteCommand – содержит текст (строку sql) или объект команды, осуществляющий удаление строки из таблицы.
4. UpdateCommand – содержит текст (строку sql) или объект команды, осуществляющий обновление значений в БД.
Порядок выполнения работы
В данном порядке выполнения лабораторной работы будет разработано приложение, которое будет работать с данными с базы данных (отображать, добавлять удалять, редактировать данные). Доступ к базе будет осуществляться с применением технологии ADO.NET. В качестве СУБД был выбран PostgreSQL. Предметная область будет состоять из двух объектов: «Группа» и «Студент», которые состоят в отношении один ко многим.
1. Установите PostgreSQL, если он у вас еще не установлен. Создайте в СУБД PostgreSQL базу данных univer, создайте в базе таблицы Groups и Students. Запросы для создания таблиц приведены ниже:
--Таблица групп
CREATE TABLE Groups(
id bigserial NOT NULL,
groupname varchar(20),
curatorname varchar(20),
headmanname varchar(20),
PRIMARY KEY (id));
--Таблица студентов
CREATE TABLE Students(
id bigserial NOT NULL,
firstname varchar(20),
lastname varchar(20),
sex varchar(1) NOT NULL CHECK (sex = 'М' or sex = 'Ж'),
age integer,
groupid bigint,
PRIMARY KEY (id),
FOREIGN KEY (groupid) REFERENCES Groups ON UPDATE CASCADE ON DELETE CASCADE);
2. Создайте новое приложение Windows Forms.
3. Добавьте в каталог с проектом библиотеку для работы с СУБД PostgreSQL. Данную библиотеку можно скачать по ссылке http://www.postgresql.org/. В данном проекте был использован архив Npgsql2.0.10-bin-ms.net.zip. Были использованы библиотеки Npgsql.dll и Mono.Security.dll.
4. Подключите библиотеку Npgsql.dll к проекту (нажмите правой кнопкой на «Ссылки» в дереве объектов, потом на «Добавить ссылку…», перейдите на закладку «Обзор», выберите необходимые файлы).
Рисунок 3.2 – Подключение библиотеки Npgsql.dll к проекту
5. Приступим к созданию главной формы. На главной форме разметите компонент MenuStrip, добавьте к нему пункт меню «Источник данных», а к пункту «Источник данных» пункты «Подключение к базе» и «Отключение от базы», создайте обработчики нажатия на эти два пункта меню.
6. Установите на форму компонент SplitConteiner для того, чтобы разделить рабочую область формы на две части.
7. Установите с левую и правую части компонент GoupBox. Установите у левого GoupBox свойство Text в значение «Группы», а у правого свойство Text в значение – «Студенты», установите у обоих GoupBox свойство Dock в значение Fill.
8. Разместите на левом и на правом GoupBox компоненты DataGridView. Установите у них свойство Dock в значение Fill. Левый DataGridView будет использоваться для отображения списка групп, а правый для отображения списка студентов в группе. Настройте каждый из DataGridView следующим образом: ReadOnly – True, MultiSelect – False, RowHeadersVisible – False, SelectionMode – FullRowSelect, AllowUserToAddRows - False.
9. Добавьте два компонента ContextMenuStrip, свяжите одно контекстное меню с левым DataGridView, а другое с правым DataGridView через свойство ContextMenuStrip. Добавьте в каждом меню три пункта «Добавить», «Удалить», «Заменить», к каждому пункту меню добавьте обработчик на нажатие.
10. Создайте три дополнительные формы. Одна будет использоваться для ввода настроек подключения, вторая - для добавления и изменения группы, третья – для добавления и изменения студента. Добавить новую форму можно нажав на проект правой кнопкой мыши, в контекстном меню выбрать «Добавить», «Создать элемент», в дереве выбрать «Windows Forms», выбрать в списке «Форма Windows Forms».
11. Приступим к реализации функций подключения к базе данных и отключения от базы данных. Откройте Form2 в режиме конструктора. Добавьте пять компонентов TextBox и компонент Button. Назовите компонент Button – «Подключиться». Первый TextBox будет использоваться для ввода адреса сервера баз данных, второй – для ввода порта, третий – для ввода имени базы данных, четвертый – для ввода имени пользователя, пятый – для ввода пароля. Компонент Button будет использоваться для подключения к базе данных. Подпишите каждое поле ввода с использованием компонента Label. Результат проектирования формы для ввода настроек подключения к базе данных приведен на рисунке 3.3.
Рисунок 3.3 – Внешний вид формы ввода настроек подключения к базе данных
12. Откройте Form2 с использованием редактора CSharp. Добавьте над конструктором формы поле:
private Form1 perent;
Это поле необходимо для доступа к родительской форме. Также добавьте метод по установлению значения этого поля:
public void setPerent(Form1 perent)
{
this.perent = perent;
}
13. Добавьте обработчик нажатия на кнопку «Подключиться»:
//Присоединиться к базе
private void button1_Click(object sender, EventArgs e)
{
string server = textBox1.Text;
int port = Int32.Parse(textBox2.Text);
string database = textBox3.Text;
string user = textBox4.Text;
string passwd = textBox5.Text;
NpgsqlConnection connection =
perent.Connect(server, port, database, user, passwd);
perent.setConnection(connection);
perent.FillDataGridView1ByGroups();
this.Visible = false;
}
Метод Connect будет реализован в главной форме позже.
14. Откройте главную форму Form1 с использованием редактора CSharp.Добавьте над конструктором формы поля:
//Ссылка на подключение
private NpgsqlConnection connection = null;
//Ссылка на DataSet
private DataSet dataSet = null;
//Ссылки на DataAdapter для группы и студента
private NpgsqlDataAdapter groupDataAdapter = null;
private NpgsqlDataAdapter studentDataAdapter = null;
//Ссылки на вспомогательные формы
private Form2 form2 = null;
private Form3 form3 = null;
private Form4 form4 = null;
Добавьте метод по установке значения поля connection:
public void setConnection(NpgsqlConnection connection)
{
this.connection = connection;
}
15. Создайте методы для получения DataSet и Form2:
//Создание DataSet
private DataSet getDataSet()
{
if (dataSet == null)
{
dataSet = new DataSet();
dataSet.Tables.Add("Groups");
dataSet.Tables.Add("Students");
}
return dataSet;
}
//Получить форму установления соединения
public Form2 getForm2()
{
if (form2 == null)
{
form2 = new Form2();
form2.setPerent(this);
}
return form2;
}
16. Добавьте метод установления соединения с базой:
//Установить соединение с базой
public NpgsqlConnection Connect(string host, int port, string database,
string user, string parol)
{
NpgsqlConnectionStringBuilder stringBuilder =
new NpgsqlConnectionStringBuilder();
stringBuilder.Host = host;
stringBuilder.Port = port;
stringBuilder.UserName = user;
stringBuilder.Password = parol;
stringBuilder.Database = database;
stringBuilder.Timeout = 30;
NpgsqlConnection connection =
new NpgsqlConnection(stringBuilder.ConnectionString);
connection.Open();
return connection;
}
17. Добавьте методы по заполнению dataGridView1 группами и dataGridView2 студентами:
//Заполнить DataGridView1 студентами
public void FillDataGridView1ByGroups()
{
getDataSet().Tables["Groups"].Clear();
groupDataAdapter = new NpgsqlDataAdapter(
"SELECT * FROM Groups", connection);
new NpgsqlCommandBuilder(groupDataAdapter);
groupDataAdapter.Fill(getDataSet(), "Groups");
dataGridView1.DataSource = getDataSet().Tables["Groups"];
}
//Заполнить DataGridView2 студентами заданной группы
public void FillDataGridView2ByStudents(string groupName)
{
getDataSet().Tables["Students"].Clear();
studentDataAdapter = new NpgsqlDataAdapter(
"SELECT Students.id, firstname, lastname, sex, age, groupid " +
"FROM Groups, Students " +
"WHERE Groups.id = Students.groupid AND groupname = '" +
groupName + "'", connection);
new NpgsqlCommandBuilder(studentDataAdapter);
studentDataAdapter.Fill(dataSet, "Students");
dataGridView2.DataSource = getDataSet().Tables["Students"];
}
18. Добавьте обработчики нажатия на пункты главного меню «Подключение к базе» и «Отключиться от базы»:
//Обработчик нажатия на "Подключиться к базе данных"
private void подключениеКБазеToolStripMenuItem_Click(
object sender, EventArgs e)
{
getForm2().Visible = true;
}
//Обработчик нажатия на "Отключиться от базы данных"
private void отключитьсяОтБазыToolStripMenuItem_Click(
object sender, EventArgs e)
{
connection.Close();
}
Функции подключения и отключения от базы реализованы, теперь приступим к реализации функций добавления, удаления и редактирования группы.
19. Откройте Form3 в режиме конструктора. Назовите форму «Группа», добавьте три компонента TextBox и два компонента Button. Первый компонент TextBox будет использоваться для ввода названия группы, второй – для ввода ФИО куратора группы, третий – для ввода ФИО старосты группы. Назовите одну кнопку «Добавить», а вторую – «Заменить». Подпишите поля ввода компонентами Label. Результат проектирования формы добавления и редактирования групп представлен на рисунке 3.4.
Рисунок 3.4 – Внешний вид формы добавления и
редактирования студентов
20. Откройте Form3 с использованием редактора CSharp. Добавьте над конструктором формы поля:
private Form1 perent = null;
private int row;
Первое поле необходимо для хранения ссылки на родительскую форму, а второе для хранения номера редактируемой строки.
21. Добавьте методы по установлению значений полей:
public void setPerent(Form1 perent)
{
this.perent = perent;
}
public void setRow(int row)
{
this.row = row;
}
22. Добавьте методы для установления свойств компонентов формы:
public void setTextBox1Text(string text)
{
textBox1.Text = text;
}
public void setTextBox2Text(string text)
{
textBox2.Text = text;
}
public void setTextBox3Text(string text)
{
textBox3.Text = text;
}
public void setButton1Visible(bool value)
{
this.button1.Visible = value;
}
public void setButton2Visible(bool value)
{
this.button2.Visible = value;
}
23. Добавьте обработчики нажатия на кнопки «Добавить» и «Заменить»:
//Добавить группу
private void button1_Click(object sender, EventArgs e)
{
perent.AddGroup(textBox1.Text, textBox2.Text, textBox3.Text);
perent.FillDataGridView1ByGroups();
this.Visible = false;
}
//Заменить группу
private void button2_Click(object sender, EventArgs e)
{
perent.UpdateGroup(row, textBox1.Text, textBox2.Text, textBox3.Text);
perent.FillDataGridView1ByGroups();
this.Visible = false;
}
Методы AddGroup и UpdateGroup будут реализованы позже в главной форме.
24. Откройте Form1 (главную форму) с использованием редактора CSharp. Добавьте метод по созданию Form3 (формы для добавления и редактирования групп):
//Получить форму добавления и замены группы
public Form3 getForm3()
{
if (form3 == null)
{
form3 = new Form3();
form3.setPerent(this);
}
return form3;
}
25. Добавьте методы по добавлению и замене группы с использованием отсоединенных объектов:
//Добавить группу
public void AddGroup(string groupName,
string curatorName, string headmanName)
{
getDataSet().Tables["Groups"].Rows.Add(0, groupName,
curatorName, headmanName);
groupDataAdapter.Update(getDataSet(), "Groups");
}
//Заменить группу
public void UpdateGroup(int row, string groupName,
string curatorName, string headmanName)
{
getDataSet().Tables["Groups"].Rows[row]["groupname"] = groupName;
getDataSet().Tables["Groups"].Rows[row]["curatorname"] = curatorName;
getDataSet().Tables["Groups"].Rows[row]["headmanname"] = headmanName;
groupDataAdapter.Update(getDataSet(), "Groups");
}
26. Добавьте обработчики нажатия на пункты «Добавить», «Удалить», «Заменить» контекстного меню для группы:
//Обработчик нажатия на "Добавить группу"
private void добавитьToolStripMenuItem_Click(object sender, EventArgs e)
{
getForm3().Visible = true;
getForm3().setButton1Visible(true);
getForm3().setButton2Visible(false);
getForm3().setTextBox1Text("");
getForm3().setTextBox2Text("");
getForm3().setTextBox3Text("");
}
//Нажатие на "Удалить группу"
private void удалитьToolStripMenuItem_Click(object sender, EventArgs e)
{
int selectedRow = dataGridView1.SelectedCells[0].RowIndex;
DialogResult dr = MessageBox.Show("Удалить группу?", "",
MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
getDataSet().Tables["Groups"].Rows[selectedRow].Delete();
groupDataAdapter.Update(getDataSet(), "Groups");
getDataSet().Clear();
FillDataGridView1ByGroups();
}
}
//Нажатие на "Заменить группу"
private void зАменитьToolStripMenuItem_Click(object sender, EventArgs e)
{
int selectedRow = dataGridView1.SelectedCells[0].RowIndex;
string groupName = (string)getDataSet().Tables["Groups"]
.Rows[selectedRow].ItemArray[1];
string curatorName = (string)getDataSet().Tables["Groups"]
.Rows[selectedRow].ItemArray[2];
string headmanName = (string)getDataSet().Tables["Groups"]
.Rows[selectedRow].ItemArray[3];
getForm3().Visible = true;
getForm3().setButton1Visible(false);
getForm3().setButton2Visible(true);
getForm3().setTextBox1Text(groupName);
getForm3().setTextBox2Text(curatorName);
getForm3().setTextBox3Text(headmanName);
getForm3().setRow(selectedRow);
}
27. Добавьте обработчик нажатия на строчку dataGridView1, чтобы в dataGridView2 отображался список заданной группы:
//Обработчик нажатия на строчку DataGridView1
private void dataGridView1_CellClick(object sender,
DataGridViewCellEventArgs e)
{
int selectedRow = dataGridView1.SelectedCells[0].RowIndex;
string key = (string)dataGridView1.Rows[selectedRow].Cells[1].Value;
FillDataGridView2ByStudents(key);
}
28. Приступим к реализации функций добавления удаления и замены студентов. Откройте Form4 (форму добавления и редактирования студентов) с использованием конструктора форм. Добавьте 4 компонента TextBox и два компонента Button. Первый компонент TextBox, будет использоваться для ввода имени студента, второй – для ввода фамилии студента, третий – для ввода пола студента, четвертый - для ввода года рождения студента. Назовите одну кнопку «Добавить», а вторую «Заменить». Подпишите каждый компонент TextBox с использование компонента Label. Результат проектирования формы добавления и замены студентов представлен на рисунке 3.5.
Рисунок 3.5 – Внешний вид формы добавления и
замены студентов
29. Откройте Form4 с использованием редактора CSharp. Добавьте над конструктором формы поля:
private Form1 perent = null;
private string groupName;
private long groupId;
private int row;
Первое поле предназначено для хранения ссылки на родительскую форму, второе для хранения имени группы, третье для хранения идентификатора группы, четвертое для хранения номера редактируемой строки.
30. Добавьте методы по установлению вышеописанных полей:
public void setPerent(Form1 perent)
{
this.perent = perent;
}
public void setGroupName(string groupName)
{
this.groupName = groupName;
}
public void setGroupId(long groupId)
{
this.groupId = groupId;
}
public void setRow(int row)
{
this.row = row;
}
31. Добавьте методы для установления свойств компонентов формы:
public void setTextBox1Text(string text)
{
textBox1.Text = text;
}
public void setTextBox2Text(string text)
{
textBox2.Text = text;
}
public void setTextBox3Text(string text)
{
textBox3.Text = text;
}
public void setTextBox4Text(string text)
{
textBox4.Text = text;
}
public void setButton1Visible(bool value)
{
this.button1.Visible = value;
}
public void setButton2Visible(bool value)
{
this.button2.Visible = value;
}
32. Добавьте обработчики нажатия на кнопки «Добавить» и «Удалить»:
//Добавить студента
private void button1_Click(object sender, EventArgs e)
{
perent.AddStudent(textBox1.Text, textBox2.Text,
textBox3.Text, Int16.Parse(textBox4.Text), groupId);
perent.FillDataGridView2ByStudents(groupName);
this.Visible = false;
}
//Заменить студента
private void button2_Click(object sender, EventArgs e)
{
perent.UpdateStudent(row, textBox1.Text, textBox2.Text,
textBox3.Text, System.Convert.ToInt32(textBox4.Text));
perent.FillDataGridView2ByStudents(groupName);
this.Visible = false;
}
Методы AddStudent, UpdateStudent будут реализованы позже в главной форме.
33. Откройте Form1 (главную форму) в режиме редактора CSharp. Добавьте метод для создания Form4:
//Получить форму добавления и замены студента
public Form4 getForm4()
{
if (form4 == null)
{
form4 = new Form4();
form4.setPerent(this);
}
return form4;
}
34. Добавьте методы для добавления и замены студента:
//Добавить студента
public void AddStudent(string firstName,
string secondName, string sex, int age, long groupId)
{
getDataSet().Tables["Students"]
.Rows.Add(0, firstName, secondName, sex, age, groupId);
studentDataAdapter.Update(getDataSet(), "Students");
}
//Заменить студента
public void UpdateStudent(int row, string firstName,
string secondName, string sex, int age)
{
getDataSet().Tables["Students"].Rows[row]["firstname"] = firstName;
getDataSet().Tables["Students"].Rows[row]["lastname"] = secondName;
getDataSet().Tables["Students"].Rows[row]["sex"] = sex;
getDataSet().Tables["Students"].Rows[row]["age"] = age;
studentDataAdapter.Update(getDataSet(), "Students");
}
35. Добавьте обработчики нажатия на пункты «Добавить», «Удалить» и «Заменить» контекстного меню студента:
//Нажатие на "Добавить студента"
private void добавитьToolStripMenuItem1_Click(object sender, EventArgs e)
{
getForm4().Visible = true;
getForm4().setButton1Visible(true);
getForm4().setButton2Visible(false);
getForm4().setTextBox1Text("");
getForm4().setTextBox2Text("");
getForm4().setTextBox3Text("");
getForm4().setTextBox4Text("");
int selectedRow = dataGridView1.SelectedCells[0].RowIndex;
long groupId = (long)getDataSet().Tables["Groups"]
.Rows[selectedRow].ItemArray[0];
string groupName = (string)getDataSet().Tables["Groups"]
.Rows[selectedRow].ItemArray[1];
getForm4().setGroupName(groupName);
getForm4().setGroupId(groupId);
}
//Нажатие на "Удалить студента"
private void удалитьToolStripMenuItem1_Click(object sender, EventArgs e)
{
int selectedRow = dataGridView2.SelectedCells[0].RowIndex;
DialogResult dr = MessageBox.Show("Удалить студента?", "",
MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
getDataSet().Tables["Students"].Rows[selectedRow].Delete();
studentDataAdapter.Update(getDataSet(), "Students");
string key = (string)dataGridView1
.Rows[selectedRow].Cells[1].Value;
FillDataGridView2ByStudents(key);
}
}
//Нажатие на "Заменить студента"
private void заменитьToolStripMenuItem1_Click(object sender, EventArgs e)
{
int selectedRow = dataGridView2.SelectedCells[0].RowIndex;
string firstName = (string)getDataSet().Tables["Students"]
.Rows[selectedRow].ItemArray[1];
string secondName = (string)getDataSet().Tables["Students"]
.Rows[selectedRow].ItemArray[2];
string sex = (string)getDataSet().Tables["Students"]
.Rows[selectedRow].ItemArray[3];
int age = (int)getDataSet().Tables["Students"]
.Rows[selectedRow].ItemArray[4];
string sAge = System.Convert.ToString(age);
getForm4().Visible = true;
getForm4().setButton1Visible(false);
getForm4().setButton2Visible(true);
getForm4().setTextBox1Text(firstName);
getForm4().setTextBox2Text(secondName);
getForm4().setTextBox3Text(sex);
getForm4().setTextBox4Text(sAge);
getForm4().setRow(selectedRow);
int selectedRow1 = dataGridView1.SelectedCells[0].RowIndex;
string groupName = (string)getDataSet().Tables["Groups"]
.Rows[selectedRow1].ItemArray[1];
getForm4().setGroupName(groupName);
}
Результат работы программы приведен на рисунке 3.6.
Рисунок 3.6 – Результат работы программы
Задание на лабораторную работу
Написать приложение, описанное в ходе выполнения лабораторной работы, которое может работать с двумя таблицами СУБД. В отличие от приложения, описанного в лабораторной работе, предметную область необходимо выбрать из таблицы 3.1. Номер варианта определяется по последней цифре зачетной книжки.
Таблица 3.1 – Варианты заданий
Номер варианта | Предметная область |
Пиццерия (Официант, Посетитель) | |
Магазин (Поставщик, Товар) | |
Супермаркет (Продавец, Товар) | |
Отделение милиции (Милиционер, Нарушитель) | |
Больница (Врач, Пациент) | |
Кинотеатр (Кинозал, Посетитель) | |
Корабль (Каюта, Пассажир) | |
Предприятие (Отдел, Сотрудник) | |
Библиотека (Книга, Читатель) |
Содержание отчета
- фамилия и имя исполнителя лабораторной работы;
- номер и название лабораторной работы;
- цель лабораторной работы;
- краткие теоретические сведенья на одну страницу;
- ход работы (листинги программ, скриншоты программ);
- выводы о проделанной работе.
Контрольные вопросы
1. Какие особенности модели доступа к данным ADO.NET?
2. Какие отличия в применении моделей доступа к данным на связном и несвязном уровнях?
3. Какие основные объекты используются для доступа к данным на связном уровне?
4. Какие основные объекты используются для доступа к данным на несвязном уровне?
4 Лабораторная работа № 4
Fluent NHibernate
Цель работы
Изучить возможности ORM Fluent NHibernate, получить практические навыки по работе с NHibernate.
Теоретические сведенья
Общие сведения об ORM
Для совмещения в одной системе преимуществ объектно-ориентированного программирования и реляционных баз данных необходимо использовать ORM (object relation mapping) – объектно-реляционное отображение. Объектно-реляционное отображение обеспечивает возможность работать с записями таблицы реляционной базы данных, как с объектом.
Суть объектно-реляционного отображения ORM (Object Relation Mapping) в том, что бы отделить хранение данных от работы с ними или иначе - разделить бизнес-логику и логику хранения/получения данных. Естественно при разработке системы отображения к ней выдвигается требование следующего плана - необходимо разработать систему таким образом, что при описании бизнес-компонентов минимум времени уходило на реализацию необходимого для этой системы отображения.
Важным достоинством отображения является возможность рассматривать отдельные таблицы БД как коллекции объектов соответствующих классов.
В технологии .NET используются два подхода для реализации отображения – на основе атрибутов или с помощью - XML-файлов для внешнего сопоставления.
Суть отображения на основе атрибутов базируется на механизме Reflection и состоит в следующем:
1. Определяются атрибуты, которые описывают, какие таблицы хранят данные соответствующих классов, и атрибуты, которые сопоставляют поля этих классов полям соответствующих таблиц. При этом отмечаются ключевые поля.
2. При описании очередной отображаемой сущности над классом определяется атрибут, который показывает, в какой таблице хранятся сущности данного типа, а над полями определяются атрибуты, которые сопоставляют им поля этих таблиц.
3. Создаётся маппер (исполнитель отображения), работа которого основана на этих атрибутах. Информацию об отображаемых полях этот маппер получает исключительно при помощи Reflection. Значения полей так же выбираются и устанавливаются через механизм Reflection.
С помощью XML-файлов метаданные для сопоставления можно хранить за пределами кода приложения. Такой файл используется для указания сопоставления между моделью данных БД и объектной моделью. Файл внешнего сопоставления имеет следующие преимущества:
1. Код сопоставления можно хранить вне кода приложения. Этот подход уменьшает перегруженность кода приложения.
2. Файл внешнего сопоставления можно считать подобным файлу конфигурации. Например, можно изменить поведение приложения после предоставления двоичных файлов, просто выгрузив файл внешнего сопоставления.
Популярными ORM для платформы .NET являются LINQ to Entities, NHibernate, Fluent NHibernate. Данная лабораторная работа посвячена ORM Fluent NHibernate – одному из наиболее удобных на данный момент.
Использование ORM Fluent NHibernate позволяет не задумываться о структуре базы данных, а работать с базой как с коллекцией связанных друг с другом объектов. Такая возможность обеспечивается благодаря механизму отображения объекта на таблицу базы данных посредством правил, которые в NHibernate задаються map-классами. В map-классе указываются правила, по которым поля объектов будут проецироваться на колонки реляционной базы данных, а также правила для связи объектов друг с другом. На этапе запуска приложения map-файлы преобразовываются в наборы запросов, которые позволяют добавлять, удалять и модифицировать данные в таблицах баз данных, а также производить выборку данных.
Кроме map-файлов в формате XML в болем поздних версиях NHibernate правила отображения можно задавать с помощью атрибутов, а в Fluent NHibernate - с помощью классов.