Опубликован: 09.09.2008 | Доступ: свободный | Студентов: 2107 / 346 | Оценка: 4.30 / 4.12 | Длительность: 08:30:00
ISBN: 978-5-94774-601-3
Самостоятельная работа 10:

Модификация, вставка и удаление записей в наборе данных

Модификация, вставка и удаление записей в наборе данных

После того, как объект DataSet заполнен данными, пользователи приложения обычно модифицируют полученную информацию, и затем эти изменения пересылаются источнику данных. Так как отдельные записи в DataSet представлены объектом DataRow, то все изменения в набор данных производятся путем модификации, добавления и удаления индивидуальных строк.

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

  • через индексы таблиц, строк и коллекций столбцов;
  • передавая в соответствующие коллекции наименования таблиц и столбцов как строковые переменные.

Модифицирование записей в типизированных и нетипизированных наборах данных осуществляется различными способами.

Наименования таблиц и столбцов в наборах данных без контроля типов (нетипизированные наборы) не доступны во времени разработки приложения и к ним нужно обращаться через их соответствующие индексы.

В типизированных наборах данных используется раннее связывание, за счет чего имена таблиц и столбцов доступны на этапе разработки приложения. Это позволяет создавать более удобочитаемый программный код. В следующем примере показано, как можно модифицировать данные в столбцах JobRoleID и EmployeeSurname пятой записи таблицы Employee в наборе данных dsEmployee1.

dsEmployee1.Employee[4].JobRoleID = 2;
dsEmployee1.Employee[4].EmployeeSurname = "Иванова";

Для добавление записей в набор данных необходимо создать новую строку и добавить ее к коллекции DataRow соответствующей таблицы. Следующий пример показывает, как вставить дополнительные строки в объект DataTable - Employee набора данных dsEmployee.

Добавление записи в набор данных происходит следующим образом.

  1. Вызовите метод таблицы данных NewRow, который создает новую пустую запись. Эта новая запись наследует коллекцию столбцов DataColumnCollection от исходной таблицы данных Employee.
    DataRow employeeRow = Employee.NewRow( );
  2. Присвойте колонкам этой строки требуемые значения .
    employeeRow[JobRoleID] = 1;
    employeeRow[EmployeeSurname] = "Ларина";
    employeeRow[EmployeeName] = "Татьяна";
    employeeRow[EmployeePatronymic] = "Ивановна";
  3. Добавьте новую запись в таблицу, вызвав метод Add объекта
    dsEmployee.Employee.Rows.Add(employeeRow);

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

Для удаления записи из таблицы данных вызовите метод Delete. Этот метод физически не удаляет запись из набора данных; он просто меняет ее статус - отмечает как удаленную запись, и она становится невидимой (перестает быть доступной конечному пользователю приложения).

Следующий пример показывает, как вызвать метод Delete для удаления первой строки таблицы Employee набора данных dsEmployee:

dsEmployee.Employee.Rows[0].Delete( );

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

Завершение изменений в наборе данных. В наборе данных при внесении изменений в записи (обновление, вставка, удаление) поддерживается и первоначальная (оригинальная), и текущая версии записей. Кроме того, в свойстве RowState каждой записи установлен признак (указатель), находятся ли запись в первоначальном состоянии или она была изменена. Эта информация необходима, когда требуется найти определенную версию строки. Как правило, в приложениях возникает необходимость передачи между компонентами только измененных записей. После того, как проведена нужная обработка всех измененных записей, можно завершить процедуру обновления, вызвав метод набора данных AcceptChanges.

Следующий пример показывает, как вызвать метод AcceptChanges для завершения изменений в таблице Employee после передачи обновлений источнику данных.

daEmployee.Update(dsEmployee, "Employee");
dsEmployee.Employee.AcceptChanges( );

Обновление баз данных из наборов данных. После того, как были сделаны изменения в наборе данных, их можно передать источнику данных. Обычно это делается путем вызова метода Update адаптера данных. Данный метод в цикле просматривает все записи таблицы и определяет, какие операции необходимо выполнить (обновление, добавление или удаление), и, если таковые вообще имеются, выполняет соответствующие команды. Если при просмотре очередной строки метода Update адаптера данных обнаруживает, что строка изменялась, то он автоматически вызовет надлежащую команду данных ( DataCommand ) и обновит на ее основе соответствующую строку в базе данных.

Структура SQL -запроса команды данных будет следующая:

  • будет задействован SQL -запрос с предложением UPDATE. Адаптер данных знает, что предложение UPDATE применяется для тех строк, свойства RowState которых имеет значение Modified ;
  • в SQL -запрос будет включено предложение WHERE, указывающее, что обновляться будет строка, для которой, например EmployeeID = 4. Эта часть SQL -запроса отличает целевую строку от всех других строк, потому что поле EmployeeID является первичным ключом таблицы базы данных. Информация для предложения WHERE будет получена не из текущей, а из оригинальной (первоначальной) версии записи ( DataRowVersion.Original ), потому что в текущей версии записи пользователь мог изменить значение первичного ключа.
  • в SQL -запрос будет включено предложение SET, для того, чтобы установить новые значения столбцов в соответствующей записи таблицы базы данных.

Обработка исключительных ситуаций при обновлении источника данных из набора данных. После того, как набор данных был изменен и эти изменения приняты, приложение должно вернуть новые данные назад источнику данных. Чтобы модернизировать источник данных содержанием набора данных вызывается метод Update адаптера данных. Адаптер данных выполнит соответствующую команду ( insert, update или delete ), используя значение свойства RowState каждой строки набора данных.

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

  1. Вызов метода Update адаптера данных должен выполняться внутри блока Try...Catch.
  2. Если возникла исключительная ситуация, то нужно определить при обработке какой строки набора данных произошла ошибка.
  3. Исправление возникшей проблемы в строке данных (либо программным способом, либо, представив пользователю ошибочную строку для внесения в нее изменений), и затем - повторная попытка модернизации источника данных.

Следующий пример показывает, как делать модернизацию источника данных внутри блока Try...catch содержанием набора данных с именем.

try
{ daEmployee.Update(dsEmployee, "Employee"); }
catch (Exception e)
{
  // Код обработки ошибочной ситуации. 
  String err = e.msg;
  MessageBox.Show("Ошибка обновления таблицы базы данных 
Employee"  + err);
}

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

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

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

  • дочерняя таблица: удалить записи;
  • родительская таблица: добавить, изменить или удалить записи;
  • дочерняя таблица: добавить или изменить записи.

Для модернизации источника данных из набора данных, который содержит две или более связанных таблиц вызовите метод Update каждого адаптера данных.

Следующий пример показывает, как модернизировать источник данных из набора данных, который содержит связанные таблицы. Чтобы следовать за вышеупомянутой последовательностью, создаются три временных набора данных дочерней таблицы, которые содержат только добавленные, только удаленные и только измененные записи. Метод Update вызывается для каждого поднабора данных внутри блока Try...catch. Если при обновлении возникнут ошибки, то они будут перехвачены и обработаны также внутри этого блока (в обработчике исключительных ситуаций). После обновления источника данных вызывается метод AcceptChanges, который "принимает" сделанные изменения и, наконец, удаляются временные наборы данных, чтобы освободить ресурсы.

void UpdateAttemp( )
{
//Набор dsl содержит только удаленные записи дочерней таблицы
DataTable dsl = anyDataset.ChildTableName.GetChanges(DataRowState.Deleted);
//Набор ds2 содержит только добавленные записи дочерней таблицы
DataTable ds2 =
anyDataset.ChildTableName.GetChanges(DataRowState.Added);
//Набор ds3 содержит только измененные записи дочерней таблицы
DataTable ds3 =anyDataset.ChildTableName.GetChanges(DataRowState.Modified);
try
{
//Удаление записей дочерней таблицы
DataAdapter2.Update(dsl); 
// Добавление и удаление записей родительской таблицы
DataAdapterl.Update(anyDataset, "ParentTable"); 
// Добавление записей в дочернюю таблицу
DataAdapter2.Update(ds2); 
// Обновление записей дочерней таблицы
DataAdapter2.Update(ds3); 
// Завершение процесса модернизации набора данных
anyDataset.AcceptChanges( ); 
// Удаление временных наборов данных
dsl.Dispose ( );
ds2.Dispose( );
ds3.Dispose( );
}
catch (Exception x)
{ 
// Обработчик ошибочных (исключительных) ситуаций.
} 
}
Листинг a.

Модификация данных

Модификация данных в приложении реализуется методом Edit. Для модификации данных необходимо для элементов контроля задать режим редактирования, вызвав метод DisplayEdit и запретить доступ к списку сотрудников в элементе listBoxEmployee. Активизация режима модификации данных по сотруднику осуществляется из пункта меню Действие/Изменить.

private void Edit ( )
{
	DisplayForm (false); 
	this.listBoxEmployee.Enabled = false;
}

При проектировании приложения использовалась технология привязки источника ( DataSet ) данных к элементам управления ( TextBox, ListBox, ComboBox ). При выводе данных на экранную форму проведенная привязка обеспечивала корректность работы приложения. При модификации данных в элементах контроля для текстового поля TextBox механизм связывания автоматически поддерживает синхронизацию между элементом контроля и источником данных. Для списка ComboBox необходимо использовать событие SelectionChangeCommitted, которое им генерируется, когда пользователь изменяет выбранный элемент и подтверждает его изменение. Обработчик этого события принимает аргумент EventArgs. Этот обработчик целесообразно использовать для получения нового значения из ComboBox, когда пользователь его изменит. Для элементов управление обработчики события SelectionChangeCommitted представлены ниже:

private void comboBoxJobRole_SelectionChangeCommitted(object sender, System.EventArgs e)
{
	// Определяем позицию в таблице Employee
	int pos = -1; 
	pos = this.BindingContext[dsEmployee1, 
"Employee"].Position;
// Изменение в таблице Employee поля JobRoleID при изменении 
// выбора должности (comboBoxJobRole) 
	dsEmployee1.Employee[pos].JobRoleID = 
(short)((DataRowView)comboBoxJobRole.Items[comboBoxJobRole.SelectedIndex])
["JobRoleID"]; 
}
private void comboBoxAccess_SelectionChangeCommitted(object sender, System.EventArgs e)
{
	int pos = -1; 
	pos = this.BindingContext[dsEmployee1, 
"Employee"].Position;
	dsEmployee1.Employee[pos].Access = 
comboBoxAccess.SelectedItem.ToString();
}

private void comboBoxStatus_SelectionChangeCommitted(object sender, System.EventArgs e)
{
	int pos = -1; 
	pos = this.BindingContext[dsEmployee1, 
"Employee"].Position;
	dsEmployee1.Employee[pos].EmployeeStatus = 
comboBoxStatus.SelectedIndex;
}
Листинг b.

Далее можно изменять данные по сотруднику на форме. После изменения данных необходимо сохранить сделанные изменения.

Сохранение данных

Сохранение данных в приложении реализуется методом Save, который активизируется при выборе пункта меню Действие/Сохранить. Для сохранения модифицированной информации в приложении необходимо вначале завершить текущее обновление всех связанных с помощью объектов Binding элементов управления Windows Forms и источника данных. Для этого необходимо вызвать метод EndCurrentEdit класса BindingManagerBase:

bmEmployee.EndCurrentEdit( )

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

DataSetEmployee.EmployeeDataTable ds1 = (DataSetEmployee.EmployeeDataTable)dsEmployee.Employee.
GetChanges(DataRowState.Modified);

Если таблица ds1 не пуста (условие - ds1 != null ) осуществляется попытка обновления базы данных с помощью метода Update адаптера daEmployee и далее уничтожается таблица ds1. Если обновить базу данных не удается, то формируется сообщение об ошибке:

if(ds1 != null)
   try
   {
     this.daEmployee.Update(ds1);
     ds1.Dispose( );
     dsEmployee.Employee.AcceptChanges(); 
   }
   catch(Exception x)
   {
     string mes = x.Message;
    MessageBox.Show("Ошибка обновления базы данных Employee "+mes, "Предупреждение");
     this.dsEmployee.Employee.RejectChanges();
   }

При завершении алгоритма обновления форма FormEmployee переводится в режим "только для чтения" с помощью метода DisplayReadOnly и фокус должен быть на элементе управления textBoxSurname.

Полный текст модифицированного метода Save приведен далее:

private void Save()
{

    string mes = "";
// Завершение текущих обновлений всех  связанных с помощью 
// объектов Binding элементов управления 
    bmEmployee.EndCurrentEdit();

///Формирование таблицы, в которую включаются только 
// модифицированные строки
    DataSetEmployee.EmployeeDataTable ds1 = (DataSetEmployee.EmployeeDataTable)dsEmployee.Employee.
GetChanges(DataRowState.Modified);

    if(ds1 != null)
        try
        {
            this.daEmployee.Update(ds1);
            ds1.Dispose( );
            dsEmployee.Employee.AcceptChanges(); 
        }
        catch(Exception x)
        {
            string mes = x.Message;
            MessageBox.Show("Ошибка обновления базы данных Employee "+mes, "Предупреждение");
            this.dsEmployee.Employee.RejectChanges();
        }
    DisplayForm(true);
    listBoxEmployee.Enabled = true;
    textBoxSurname.Focus();
}
Листинг c.

Протестируйте добавленный в программу код.

Анна Иваненко
Анна Иваненко

В самостоятельной работе 8 написано: "В пункте "Server name" задаем имя сервера, которое необходимо узнать у преподавателя". Где узнать это имя?

Вячеслав Шестивский
Вячеслав Шестивский

Вроде всё выставил верно, но при клике на "Сотрудники", меню из FormEmplyee не вставляется в меню главного окна а висит в дочернем окне снизу.  Как поправить?