Основные концепции обновления наборов данных в Microsoft. NET

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

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

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

На рисунке 10.1 приведен иллюстративный пример обновления полей EmployeeSurname и EmployeeName таблицы Employee в соответствии с двухступенчатой схемой обновления данных в DataSet.

Рис. 10.1. Схема двухступенчатого обновления данных в DataSet

 

Информация в объекте DataSet доступна через его коллекции. Набор данных содержит коллекцию таблиц (DataTable). Таблица содержат коллекции строк (DataRow). Строка содержит коллекцию колонок (DataColumn). Внесение изменений в наборе данных происходит путем навигации по элементам коллекции и модификации значений конкретных колонок. В объекте DataSet имеется набор методов, которые позволяют модифицировать только сам набор записей (их используют тогда, когда заведомо известно, что обновления не будут передаваться источнику данных). И есть набор методов, которые позволяют обновить информацию, как в наборе данных, так и в источнике данных.

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

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

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

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

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

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

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

Информация об изменениях в наборе данных поддержана двумя способами: наличие в каждой строке признака, указывающего на факт внесения изменения в строку (RowState), сохранение нескольких копий (версий) строки (DataRowVersion). На основе этой информации можно однозначно определить, что изменялось в наборе данных и куда адресовать эти изменения в источнике данных.

Объект DataRow имеет свойство DataRowState, в котором хранится информация о состоянии строки данных. В таблице 10.1 приведены возможные значения свойства DataRowState.

Таблица 10.1. Значения свойства DataRowState объекта DataRow

Значение свойства Описание
Added Строка была добавлена к коллекции строк DataRowCollection (для этой строки существует только текущая версия в наборе данных и отсутствует соответствующая оригинальная версия). Ее не было в наборе данных на момент последнего вызова метода AcceptChanges
Deleted Строка была удалена использованием метода DataRow.Delete объекта DataRow
Detached Строка была создана, но еще не является элементом коллекции DataRowCollection. Объект DataRow находится в этом состоянии сразу после того, как был создан, но еще не добавлен к коллекции, или если он был специально удален из коллекции
Modified Значение столбца в строке было изменено
Unchanged Строка не изменялась с тех пор, как был вызван метод AcceptChanges

Наборы данных поддерживают множественные версии записей. Объект DataRow имеет свойство DataRowVersion, в котором хранится информации о версии каждой строки. В таблице 10.2 приведены возможные значения свойства DataRowVersion.

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

Таблица 10.2. Значения свойства DataRowVersion объекта DataRow

Значение свойства Описание
Current Текущая версия записи. В этой строке содержатся все изменения, выполненные с момента последнего вызова метода AcceptChanges. Если строка была удалена, то у нее нет текущей версии
Default Значение по умолчанию (как определено схемой набора данных или источником данных)
Original Первоначальная (оригинальная) версия записи. Состояние записи до того, как в нее были внесены какие-либо изменения. Практически эта та версия записи, которая была получена от источника данных
Proposed Промежуточная версия записей, которая существует временно (в режиме внесения в нее изменений). То есть она существует в промежуток времени между вызовами методов начала редактирования (BeginEdit) и завершением редактирования (EndEdit). Вы можете обратиться к этой версии записи в обработчике события RowChanging. Вызов метода CancelEdit полностью отменит все внесенные в строку изменения и удалит промежуточную версию строки данных

 

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

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

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

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

Обычно при работе с приложением модифицируются не все записи в наборе данных. Наборы данных и таблицы данных поддерживают метод GetChanges, что позволяет возвратить только те строки, в которые вносились изменения.

Можно создать любые подмножества измененных записей, используя метод GetChanges для любой таблицы данных (DataTable.GetChanges) или для всего набора данных (Dataset.GetChanges). Если был вызван метод для таблицы данных, то в результате его работы будет возвращена копия таблицы только с измененными записями. Точно так же, если был вызван метод для набора данных, то будет сформирован новый набор данных только с измененными записями этого набора. Вызов метода GetChanges без указания статуса строк, позволит получить все измененные записи. Если методу GetChanges передать в качестве параметра статус строки (DataRowState), тогда можно получить нужное подмножество измененных записей: только добавленные записи, записи, отмеченные для удаления, отдельные записи (не являющиеся элементами коллекции строк), модифицированные записи.

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

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

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

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

Можно завершить поддержку обработки изменений набора данных, вызвав метод AcceptChanges (принять изменения). Как правило, метод AcceptChanges вызывается в приложении в двух случаях:

  • после загрузки набора данных. Если набор данных был загружен путем вызова метода Fill в адаптер данных, то адаптер данных автоматически завершает процедуру поддержки изменений;
  • после того, как изменения в наборе данных были пересланы другому процессу, типа XML Web-service.

Работа метода AcceptChanges приводит к следующему результату:

  • значения колонок текущей (current) версии записей переносятся в колонки первоначальной (original) версии записей (поверх имеющихся там данных);
  • удаляются все строки, свойство которых RowState имеет значение Deleted;
  • свойству всех записей RowState присваивается значение Unchanged.

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

В таблице 10.3 показано, какие изменения будут завершены в зависимости от того, к какому объекту адресован метод AcceptChanges.

Таблица 10.3. Результат работы метода AcceptChanges

Метод Результат работы метода
DataRow.AcceptChanges Завершение изменений только в определенной строке
DataTable.AcceptChanges Завершение изменений во всех строках определенной таблицы
DataSet.AcceptChanges Завершение изменений во всех строках, во всех таблицах набора данных

С методом AcceptChanges связан другой метод - RejectChanges, который выполняет противоположное действие - отменяет все изменения. При вызове метода RejectChanges происходит копирование столбцов строки первоначальной версии в строку текущей версии, а свойству RowState каждой записи присваивается значение Unchanged.

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

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

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

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

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

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

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

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

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

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

  1. Вызовите метод таблицы данных NewRow, который создает новую пустую запись. Эта новая запись наследует коллекцию столбцов DataColumnCollection от исходной таблицы данных Employee.
2. DataRow employeeRow = Employee.NewRow();
  1. Присвойте колонкам этой строки требуемые значения.
4. employeeRow[JobRoleID] = 1;5. employeeRow[EmployeeSurname] = "Ларина";6. employeeRow[EmployeeName] = "Татьяна";7. employeeRow[EmployeePatronymic] = "Ивановна";
  1. Добавьте новую запись в таблицу, вызвав метод Add объекта
9. 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){ // Обработчик ошибочных (исключительных) ситуаций.} }

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

Модификация данных в приложении реализуется методом 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;}

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

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

Сохранение данных в приложении реализуется методом 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();}

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

 Добавление данных

Создание новой записи с данными по сотруднику в приложении реализуется методом New. При добавлении новых записей в таблицу Employee базы данных необходимо:

  1. Создать новую строку
2. DataRow rowEmployee = this.dsEmployee.Employee.NewEmployeeRow();
  1. Сформировать начальные значения для элементов строки
4. rowEmployee["JobRoleID"] = 1;5. rowEmployee["EmployeeStatus"] = 0;6. rowEmployee["EmployeeSurname"] = "";7. rowEmployee["EmployeeName"] = "";8. rowEmployee["EmployeePatronymic"] = "";9. rowEmployee["Access"] = "не задано";
  1. Добавить сформированную строку к таблице Employee
11.dsEmployee.Employee.Rows.Add(rowEmployee);
  1. Установить активную позицию в таблице Employee на добавленную строку
13.int pos = this.dsEmployee.Employee.Rows.Count - 1;14.this.BindingContext[dsEmployee, EmployeeID].Position = pos;
  1. Задать режим редактирования формы
16.DisplayForm(false);
  1. Сделать список сотрудников недоступным для выбора
18.listBoxEmployee.Enabled = false;
  1. Установить фокус на элементе textBoxSurname
20.textBoxSurname.Focus();

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

/// Формирование таблицы, в которую включаются только добавленные строкиDataSetEmployee.EmployeeDataTable ds2 = (DataSetEmployee.EmployeeDataTable)dsEmployee.Employee.GetChanges(DataRowState.Added);if(ds2!= null) try { daEmployee.Update(ds2); ds2.Dispose(); dsEmployee.Employee.AcceptChanges(); } catch(Exception x) { string mes = x.Message; MessageBox.Show("Ошибка вставки записи в базу данных Employee "+mes, "Предупреждение"); this.dsEmployee.Employee.RejectChanges(); }

В добавляемом фрагменте проверяется наличие в таблице Employee добавленных строк

ds2!= null

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

daEmployee.Update(ds2);

При вставке новых записей в базу данных метод Update адаптера daEmployee вызывает SQL команду INSERT, которая была сформирована при генерации адаптера. Если первичный ключ таблицы базы данных является суррогатным и генерируется сервером автоматически (задано свойство IDENTITY), которое корректируется в DataSet.

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

Удаление данных

Удаление записи с данными по сотруднику в приложении реализуется методом Remove. В процессе удаления записей по сотрудника используется модальное диалоговое окно для вывода сообщения (см. лабораторную работу 4), вид которого представлен на рисунке 10.2, для предупреждения пользователя при проведении операции.


Рис. 10.2. Диалоговое окно предупреждения пользователя.

При выборе пункта меню Действие/Удалить формируется событие, которое обрабатывается методом toolStripButtonRemove_Click. Обработчик вызывает метод Remove, который выполняет удаление данных по сотруднику. В методе Remove определяется позиция, которую необходимо удалить в таблице Employee

int pos = -1;pos = this.BindingContext[dsEmployee, "Employee"].Position;

Затем формируется строка с фамилией, именем и отчеством, удаляемого сотрудника

string mes = textBoxSurname.Text.ToString().Trim() + " "   + textBoxName.Text.ToString().Trim() + " " + textBoxPatronymic.Text.ToString().Trim();

и выводится сообщение в диалоговом окне

MessageBox.Show(" Удалить данные \n по сотруднику \n"+ mes+ "?", "Предупреждение",   MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);

Далее в зависимости от того, какую кнопку нажал пользователь, осуществляется удаление записи. Если пользователь нажал кнопку "Да", то необходимо выполнить следующий код:

this.dsEmployee.Employee.Rows[pos].Delete();if (this.dsEmployee.Employee.GetChanges(DataRowState.Deleted)!= null){ try { this.daEmployee.Update(dsEmployee.Employee); this.dsEmployee.Employee.AcceptChanges(); } catch (Exception x) { string er = x.Message.ToString(); MessageBox.Show("Ошибка удаления записи в базе данных Employee " + er, "Предупреждение"); this.dsEmployee.Employee.RejectChanges(); }}

При нажатии кнопки "Нет", то необходимо выполнить код:

this.dsEmployee.Employee.RejectChanges();

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


Отмена изменений

Отмена модификации записи с данными по сотруднику в приложении реализуется методом Undo. При отмене изменений необходимо завершить текущие обновления связанных элементов управления

bmEmployee.EndCurrentEdit();

и с помощью метода RejectChanges отменить изменения в источнике данных

dsEmployee.Employee.RejectChanges();

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: