Обратите внимание на способ создания параметра и добавления его в коллекцию параметров команды SELECT. Параметр команды используется в условии отбора (оператор where), его значение выбирается из ComboBox.
В настоящий момент вы владеете основными способами работы с объектами DbCommand, DbDataReader и DataView. Поэтому пора вернуться к задаче обновления данных связанных таблиц, осложненной тем, что в паре ключей PK-FK (Primary Key-Foreign Key) первичный ключ является автоинкрементируемым счетчиком.
Проблемы внесения изменений в базу данных, которые мы рассмотрели ранее, обусловлены сложной структурой данных ADO.NET, когда одновременно существует несколько версий строк таблицы и в процессе работы с ними строки переходят из одного состояния в другое. Адаптер связи (и его метод Update) разработан для работы только с одной таблицей и плохо приспособлен для обновления данных с иерархической структурой.
Разрабатывая приложение, решаюшее описанную проблему, мы поступим следующим образом. Создадим класс TablesChange, объект которого будет накапливать и оптимизировать все изменения, которые производятся над строками таблиц БД в прцессе работы пользователя с таблицами Studs и Exams. Манипуляция данными производится с помощью компонентов gridStuds и gridExams класса DataGridView.
· Скопируйте решение StudentsOleDb и переименуйте копию (решение и проект) в StudentsDBEx.
· С помощью рефакторинга переименуйте пространство имен (namespace) в StudentsDBEx.
· Убедитесь, что BindingNavigator имеет обработчик события ItemClicked.
· Добавьте в проект новый класс TablesChange.
· Введите следующий код в файл TablesChange.cs
namespace StudentsDBEx
{
public class TablesChange
{
List<DataRow>[] added, deleted, changed;
DataTableCollection tables;
public List<DataRow>[] Added { get { return added; } }
public List<DataRow>[] Deleted { get { return deleted; } }
public List<DataRow>[] Changed { get { return changed; } }
public TablesChange (DataTableCollection col)
{
tables = col;
int count = tables.Count;
added = new List<DataRow>[count];
deleted = new List<DataRow>[count];
changed = new List<DataRow>[count];
for (int i=0; i<count; i++)
{
added[i] = new List<DataRow> ();
deleted[i] = new List<DataRow>();
changed[i] = new List<DataRow>();
}
}
internal void RowChanged (object sender, DataRowChangeEventArgs e)
{
int id;
for (id = 0; sender != tables[id]; id++)
;
DataRow row = e.Row;
List<DataRow>
newRows = added[id],
modRows = changed[id],
delRows = deleted[id];
switch (e.Action)
{
case DataRowAction.Add:
if (!newRows.Contains (row))
newRows.Add (e.Row);
break;
case DataRowAction.Change:
if (!newRows.Contains (row) && !modRows.Contains (row))
modRows.Add (e.Row);
break;
case DataRowAction.Delete:
if (newRows.Contains (row))
newRows.Remove (row);
else
{
if (modRows.Contains (row))
modRows.Remove (row);
if (!delRows.Contains (row))
{
DataRow copy = tables[id].NewRow ();
foreach (DataColumn col in tables[id].Columns)
copy[col] = row[col];
delRows.Add (copy);
}
}
break;
}
}
internal void Clear ()
{
for (int i = 0; i < tables.Count; i++)
{
added[i].Clear ();
deleted[i].Clear ();
changed[i].Clear ();
}
}
}
}
В состав данных класса входит типизированная коллекция ссылок на таблицы DataTableCollectiontables и три массива объектов, каждый из которых является generic-списком ссылок на те объекты DataRow, которые претерпели изменения. Generic-списки, построенные на основе шаблонов List<DataRow>, оптимально работают с объектами определенного типа. В нашем случае они настроены на хранение объектов DataRow.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.