Читать в оригинале

<< ПредыдущаяОглавлениеСледующая >>


4.4.2. Объект DataRow

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

 

Программное создание и изменение записей таблицы данных

 

Создадим новое Windows-приложение. В конструкторе формы создаем экземпляр dtTours и поля, соответствующие таблице «Туры»:

public Form1()
{
          InitializeComponent();
          DataTable dtTours = new DataTable();
          DataColumn ddDtour = dtTours.Columns.Add("Код тура", typeof(Int32));
          dclDtour.Unique = true;
          DataColumn dcName = dtTours.Columns.Add("Название");
          DataColumn dcPrice = dtTours.Columns.Add("Цена", typeof(Decimal));
          DataColumn dcInformation = dtTours.Columns.Add("Информация");
          DataView myDataView = new DataView(dtTours);
          dataGrid1.DataSource = myDataView;
}

Для того чтобы привязать созданные данные к элементу управления DataGridView, понадобилось создать экземпляр myDataView класса DataView. Каждый объект DataTable содержит объект DataView, причем этот объект, используемый по умолчанию, называется DataTable.DefaultView. Данный объект неоднократно использовался ранее, например, в предыдущем проекте для вывода данных:

dataGrid1.DataSource = dsTours.Tables["Туры"].DefaultView;

Один объект DataTable может иметь несколько объектов DataView - это удобно для вывода одних и тех же данных, отфильтрованных или отсортированных различным образом. Запускаем приложение. На экранной форме представлена готовая структура таблицы «Туры» (рис. 110).

Рис. 110. Структура таблицы «Туры»

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

DataRow myRow = dtTours.NewRow();
myRow["Код тура"] = 1;
myRow["Название"] = "Кипр";
myRow["Цена"] = 25000;
myRow["Информация"] = "В стоимость двух взрослых путевок входит цена одной детской (до 7лет)";
dtTours.Rows.Add(myRow);

Запускаем приложение (рис. 111). В таблице появилась первая запись.

Рис. 111. Добавление записи в таблицу

Добавим еще одну запись:

DataRow myRow2 = dtTours.NewRow();
myRow2["Код тура"] = 2;
myRow2["Название"] = "Греция";
myRow2["Цена"] = 32000;
myRow2[" Информация"] = "В августе и сентябре действуют специальные скидки";
dtTours.Rows.Add(myRow2);

Название, указываемое в квадратных скобках объектов myRow или myRow2, представляет собой имя столбца, которое мы определили в самом начале.

К столбцу можно обращаться и по индексу. Для демонстрации создадим следующий код:

DataRow myRow = dtTours.NewRow();
myRow[0] = 1;
myRow[1] = "Кипр";
myRow[2] = 25000;
myRow[3] = "В стоимость двух взрослых путевок входит цена одной детской (до 7лет)";
dtTours.Rows.Add(myRow);
DataRow myRow2 = dtTours.NewRow();
myRow2[0] = 2;
myRow2[1] = "Греция";
myRow2[2] = 32000;
myRow2[3] = "В августе и сентябре действуют специальные скидки";
dtTours.Rows.Add(myRow2);

Нумерация столбцов начинается с нуля.

Более удобный способ добавления записей - применение свойства ItemArray объекта DataRow, где можно задавать значения полей в виде массива:

DataRow myRow3 = dtTours.NewRow();
myRow3.ItemArray = new object[] { 3, "Таиланд", 30000, null };
dtTours.Rows.Add(my Row3);

Здесь мы указали значение поля «Информация», равное null, - таким образом можно пропускать неизвестные поля (рис. 112).

Рис. 112. Вставка записи с одним значением null

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

Изменим текущий проект. В коде проекта после отображения данных в элементе DataGrid:

dataGrid1.DataSource = dsTours.Tables["Туры"].DefaultView;

будем добавлять соответствующие строки.

Для изменения, например, пятой строки, мы указываем в свойстве Rows объекта dtTours ее индекс, равный числу 4, так как нумерация полей в строке начинается с нуля, затем вызываем метод BeginEdit для начала редактирования, устанавливаем группу свойств и в заключение принимаем изменения, вызывая метод EndEdit:

DataRow myRow=dtTours.Rows[4];

myRow.BeginEdit();
myRow["Код тура"] = 5;
myRow["Название"] = "Турция";
myRow["Цена"] = "27000";
myRow["Информация"] = "Осенние скидки с 15 октября";
myRow.EndEdit();

Тот же самый результат мы получим с помощью свойства ItemArray:

DataRow myRow=dtTours.Rows[4];
myRow.BeginEdit();
myRow.ItemArray = new object[] {5,"Турция", 27000, null, null, "Осенние скидки с 15 октября"};
myRow.EndEdit();

Здесь мы установили для третьего и четвертого полей, которые являются вычисляемыми, значения null, подразумевая, что они останутся по умолчанию, а при запуске заполнятся своими значениями (рис. 113).

Рис. 113. Пропущенные вычисляемые поля заполняются своими значениями

Для удаления заданной записи нужно создать объект DataRow, которому передается индекс строки, а затем вызвать метод Remove свойства Rows объекта DataTable:

DataRow myRow2 = dtTours.Rows[0];
dtTours.Rows.Remove(myRow2);

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

myRow2.Delete();

В результате у нас удалится строка (рис. 114), причем объект DataTable пометит ее в качестве удаленной - это необходимо, чтобы избежать ошибок (например, в связанных записях).

Рис. 114. Первая строка, имеющая индекс 0, была удалена

 

 

Свойство RowState

 

При работе с данными приходится постоянно вносить изменения в записи - добавлять, редактировать или удалять. Объект DataRow обладает свойством RowState, позволяющим отслеживать текущий статус строки.

Создадим новое приложение. В конструкторе формы мы создадим всего одно поле, затем одну запись, статус которой будем отслеживать:

public Form1() {
          InitializeComponent();
          DataTable dtTours = new DataTable("Туры");
          DataColumn IDtour = new DataColumn("Код тура", typeof(Int32));
          dtTours.Columns.Add(IDtour);
          dataGrid1.DataSource = dtTours;
          DataRow myRow;
// Создаем новую, отсоединенную запись
          myRow = dtTours.NewRow();
          richTextBox1.Text += Convert.ToString("Новая запись: " + myRow.RowState);
//Добавляем запись в объект
          DataTable dtTours.Rows.Add(myRow);
          richTextBox1.Text += Convert.ToString("\nДобавление записи: " + myRow.RowState);
//Принимаем все изменения в объекте
          DataTable dtTours.AcceptChanges();
          richTextBox1.Text += Convert.ToString("\nМетод AcceptChanges: " + myRow.RowState);
//Редактируем запись
          myRow["Код тура"] = 1;
          richTextBox1.Text += Convert.ToString("\n Редактирование строки: " + myRow.RowState);
//Удаляем строку
          myRow.Delete();
          richTextBox1.Text += Convert.ToString("\nУдаление: " + myRow.RowState);
//Отменяем все изменения в объекте
          DataTable dtTours.RejectChanges();
          richTextBox1.Text += Convert.ToString("\n Метод RejectChanges: " + myRow.RowState);
}

Запускаем приложение. В текстовое поле выводится статус записи myRow (рис. 115).

Значение Detached означает, что запись не относится к объекту DataTable. После добавления ее статус изменяется на Added - теперь она существует в объекте DataTable, но ее нет в базе данных. Конечно, здесь не рассматривается взаимодействие с источником записей, но это же значение будет у записей, добавляемых в DataGrid после вывода данных из базы при наличии подключения. Вызывая метод AcceptChanges объекта DataTable, выполняется прием всех изменений, поэтому статус DataRow изменяется на Unchanged - теперь запись считается «своей», она не была изменена после вызова метода. После вызова метода Delete запись помечается удаленной - она еще не полностью удалена, в случае отмены изменений статус будет восстановлен. Действительно, вызов метода RejectChanges объекта DataTable восстанавливает запись до состояния Unchanged.

Рис. 115. Приложение RowState

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

 

Свойство RowVersion

 

Свойство RowVersion предназначено для извлечения значения записи (объекта DataRow), зависящего от совершенных изменений. Возможны следующие версии записи:

- Current - текущее значение

- Default - значение по умолчанию

- Original - первоначальное значение

- Proposed - предполагаемое значение

Создадим новое приложение. В классе формы объявим объекты DataRow и DataTable: DataRow myRow; DataTable dtTours;

В конструкторе формы создаем запись, определяем источник данных для элемента DataGridView, а также отключаем его доступность:

public Form1() {
          InitializeComponent();
          dtTours = new DataTable("Туры");
          DataColumn IDtour = new DataColumn("Название", typeof(string));
          dtTours.Columns.Add(IDtour);
          myRow = dtTours.NewRow();
          dtTours.Rows.Add(myRow);
          myRow["Название"] = "Таиланд";
          dataGrid1.DataSource = dtTours;
          dataGrid1.Enabled = false;
}

Создадим метод TestRowVersion, в котором будет проверяться свойство RowVersion записи:

private void TestRowVersion() {
          if(myRow.HasVersion(DataRowVersion.Original))
            rtbReport.Text += String.Format("Значение original: {0}\n",
                        myRow[" Название", DataRowVersion.Original]);
          if(myRow.HasVersion(DataRowVersion.Current))
            rtbReport.Text += String.Format("Значение current: {0}\n",
                        myRow[" Название", DataRowVersion.Current]);
          if(myRow.HasVersion(DataRowVersion.Default))
            rtbReport.Text += String.Format("Значение default: {0}\n",
                        myRow[" Название", DataRowVersion.Default]);
          if(myRow.HasVersion(DataRowVersion.Proposed))
            rtbReport.Text += String.Format("Значение proposed: {0}\n",
                        myRow["Название", DataRowVersion.Proposed]);
}

Метод HasVersion позволяет определить, поддерживает ли объект myRow версию данных, указываемую в скобках. В случае подтверждения будет выполняться код оператора - выводится в элемент rtbReport соответствующее сообщение.

В обработчике кнопки btnBeginEdit (Редактировать) вызываем метод BeginEdit, устанавливаем новое значение записи:

private void btnBeginEdit_Click(object sender, System.EventArgs e) {
          myRow.BeginEdit();
          myRow["Название"] = "Франция";
          rtbReport.Text += "BeginEdit\n";
          TestRowVersion();
}

В обработчике кнопки btnEndEdit завершаем редактирование записи:

private void btnEndEdit_Click(object sender, System.EventArgs e) {
         myRow.EndEdit();
         rtbReport.Text += "EndEdit\n";
         TestRowVersion();
}

В обработчике кнопки btnCancelEdit отказываемся от внесенных изменений:

private void btnCancelEdit_Click(object sender, System.EventArgs e) {
         myRow.CancelEdit();
         rtbReport.Text += "CancelEdit\n";
         TestRowVersion();
}

В обработчике кнопки btnDelete удаляем объект myRow:

private void btnDelete_Click(object sender, System.EventArgs e) {
         myRow. Delete();
         rtbReport.Text += "Запись удалена\n";
         TestRowVersion();
}

В обработчике кнопки «Очистить отчет» просто удаляем содержимое текстового поля:

private void btnClear_Click(object sender, EventArgs e) {
          this.rtbReport.Text = "";
}

Запускаем приложение.

После нажатия кнопки «Begin Edit» мы начинаем редактирование записи, вводится новое значение - «Франция». Оно становится значением по умолчанию (Default) и предполагаемым Proposed, значение «Таиланд» является текущим (Current) (рис. 116).

Рис. 116. Демонстрация работы. Шаг 1 - Редактирование

Отменяем редактирование, нажимая кнопку «Cancel Edit». При этом значение «Таиланд» становится текущим (Current) и по умолчанию (Default) (рис. 117).

Рис. 117. Демонстрация работы. Шаг 2 - Отмена редактирования

Снова начинаем редактирование - картина повторяется (рис. 118).

Рис. 118. Демонстрация работы. Шаг 3 - Повторное редактирование

На этот раз завершаем редактирование, нажимая кнопку «End Edit» - новое значение «Франция» становится текущим (Current) и по умолчанию (Default) (рис. 119).

Рис. 119. Демонстрация работы. Шаг 4 - Завершение редактирования

Теперь нажимаем кнопку «Удалить» - при этом удаляется сам объект myRow и дальнейшее изменение его значений оказывается невозможным (рис. 120).

Рис. 120. Демонстрация работы. Шаг 5 - Удаление

 

События объекта DataTable

 

Объект DataTable содержит ряд событий, которые могут применяться для слежения за происходящими изменениями. Наиболее часто используются следующие события:

            ColumnChanged - наступает после изменения содержимого поля таблицы;
            ColumnChanging - происходит в течение редактирования содержимого поля таблицы;
         RowChanged - наступает после изменения объекта DataRow (записи);
         RowChanging - происходит в течение редактирования объекта DataRow;
         RowDeleted - наступает после удаления объекта DataRow;
         RowDeleting - происходит при удалении объекта DataRow.

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

public Form1() {
         dtTours.RowChanging += new DataRowChangeEventHandler(dtTours_RowChanging);
         dtTours.RowChanged += new DataRowChangeEventHandler(dtTours_RowChanged);
         dtTours.RowDeleting += new DataRowChangeEventHandler(dtTours_RowDeleting);
         dtTours.RowDeleted += new DataRowChangeEventHandler(dtTours_RowDeleted);
}

В соответствующих методах просто выводим сообщение в текстовое поле:

private void dtTours_RowChanging(object sender, DataRowChangeEventArgs e) {
          rtbReport.Text += String.Format(“Событие - изменение записи\n", e.Row["Название"]);
}
private void dtTours_RowChanged(object sender, DataRowChangeEventArgs e) {
          rtbReport.Text += "\nСобытие - запись изменена\n";
}
private void dtTours_RowDeleting(object sender, DataRowChangeEventArgs e) {
          rtbReport.Text += String.Format(“Событие - удаление записи\n", e.Row["Название"]);
}
private void dtTours_RowDeleted(object sender, DataRowChangeEventArgs e) {
          rtbReport.Text += "\nСобытие - запись удалена\n";
}

Запускаем приложение.

Нажимаем кнопку «Begin Edit», затем «End Edit» - происходят события RowChanging и RowChanged. Удаляем запись - происходят события RowDeleting и RowDeleted (рис. 121).

Рис. 121. Демонстрация событий таблиц

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

 



<< ПредыдущаяОглавлениеСледующая >>