Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_CSharp_4.docx
Скачиваний:
37
Добавлен:
02.11.2018
Размер:
237.61 Кб
Скачать

4.8. Объекты класса DataRow – строки таблицы

Строки содержат данные таблицы. Отдельная строка представлена объектом класса DataRow. Таблица содержит коллекцию Rows для хранения своих строк. Каждая строка обладает свойством Table, в котором хранится ссылка на таблицу, владеющую строкой.

Для создания строки применяется метод таблицы NewRow(). Метод генерирует пустую строку согласно структуре таблицы, но не добавляет эту строку в таблицу. Для добавления строки необходимо заполнить ее данными, а затем воспользоваться методом DataTable.Rows.Add(). Существует перегруженный вариант этого метода, который принимает в качестве параметра массив объектов, являющихся значениями полей строки:

var Artists = new DataTable("Artists");

// после создания таблицы добавили в неё объекты-столбцы

// создали пустую строку с требуемой структурой

var r = Artists.NewRow();

// заполняем её содержимым

r["name"] = "Metallica";

// добавляем в таблицу

Artists.Rows.Add(r);

// вариант покороче, в котором совмещены сразу три действия

Artists.Rows.Add(new object[] { null, " Metallica" });

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

// знаем номер строки, в данном случае – получаем вторую

DataRow row = Users.Rows[1];

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

// меняем содержимое определенных полей строки

row["user_name"] = "the user ";

row["user_address"] = "the address";

Платформа .NET версии 3.5 содержит класс DataRowExtensions с двумя универсальными методами расширения для класса DataRow: Field<T>() и SetField<T>(). Эти методы позволяют осуществить типизированный доступ к полям строки. Как и индексаторы DataRow, методы имеют различные перегруженные версии.

int id = row.Field<int>(0);

row.SetField<int>("id", 25);

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

row.BeginEdit();

row["user_name"] = "the user";

row["user_address"] = "the address";

row.EndEdit();

Есть ещё одно отличие между этими двумя способами редактирования. Объект DataTable предоставляет события RowChanging, RowChanged, ColumnChanging и ColumnChanged, с помощью которых удаётся отслеживать изменения строки или поля. Порядок наступления этих событий зависит от того, как редактируется строка – с вызовом методов BeginEdit() и EndEdit() или без них. Если вызван метод BeginEdit(), наступление событий откладывается до вызова EndEdit() (если вызвать CancelEdit() никакие события не наступают).

Третий способ изменения строки – воспользоваться свойством строки ItemArray, Свойство ItemArray позволяет просматривать и редактировать содержимое строки, но его тип – это массив, элементы которого соответствуют полям строки. Если необходимо отредактировать содержимое лишь некоторых полей, воспользуйтесь литералом null.

// меняем содержимое второго и третьего полей

row.ItemArray = new object[] { null, "the user", "the address" };

Чтобы удалить строку, достаточно вызвать метод Delete() объекта DataRow. После вызова метода Delete() строка помечается как удаленная, из базы она будет удалена после «закачки» содержимого DataSet в базу. Можно удалить строку из коллекции Rows таблицы, воспользовавшись методами коллекции Remove() или RemoveAt(). Если строка удалена подобным образом, то при синхронизации изменений с БД, из базы строка удалена не будет.

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

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

  • Unchanged – строка не менялась (совпадает со строкой в базе);

  • Detached – строка не относится к объекту DataTable;

  • Added – строка добавлена в объект DataTable, но не существует в БД;

  • Modified – строка была изменена по сравнению со строкой из базы;

  • Deleted – строка ожидает удаления из базы.

В табл. 7 показано, как может изменяться состояние отдельной строки.

Таблица 7

Изменение состояния строки DataRow

Действие

Код

Значение

RowState

Создание строки, не относящейся к объекту DataTable

row = tbl.NewRow();

row["id"] = 100;

Detached

Добавление новой строки в DataTable

tbl.Rows.Add(row);

Added

Получение существующей строки

row = tbl.Rows[0];

Unchanged

Редактирование строки

row.BeginEdit();

row["id"] = 10000;

row.EndEdit();

Modified

Удаление строки

row.Delete();

Deleted

С помощью свойства RowState можно найти в таблице изменённые строки. Кроме этого, для любой строки существует возможность просмотреть, каким было значение ее полей до изменения. Индексатор строки и методы расширения Field<T>() и SetField<T>() имеют перегруженные версии, принимающий значение из перечисления DataRowVersion:

  • Current – текущее значение поля;

  • Original – оригинальное значение поля;

  • Proposed – предполагаемое значение поля (действительно только при редактировании записи с использованием BeginEdit()).

Следующий фрагмент кода изменяет содержимое поля name первой строки таблицы Songs, а затем выводит оригинальное и текущее содержимое поля:

var Songs = new DataTable("Songs");

// заполняем таблицу из базы, чтобы была "оригинальная" версия

var da = new SqlDataAdapter("SELECT * FROM Songs", "Server=. . .");

da.Fill(Songs);

// меняем содержимое первой строки

var row = Songs.Rows[0];

row["name"] = "NAME";

Console.WriteLine(row["name", DataRowVersion.Current]);

Console.WriteLine(row["name", DataRowVersion.Original]);

Табл. 8 показывает возможные значения, возвращаемые индексатором в зависимости от указанной версии ([Искл.] обозначает генерацию исключительной ситуации при попытке получить определенную версию).

Таблица 8

Значения свойства Item в зависимости от версии строки

Пример

Current

Original

Proposed

Только что созданная строка, не связанная с таблицей

row = tbl.NewRow();

row["id"] = 10;

[Искл.]

[Искл.]

10

В таблицу добавлена новая строка

tbl.Rows.Add(row);

10

[Искл.]

[Искл.]

Данные загружены из базы, из таблицы получена существующая строка

row = tbl.Rows[0];

11

1

[Искл.]

Первое изменение существующего поля

row.BeginEdit();

row["id"] = 100;

1

1

100

После первого изменения

row.EndEdit();

100

1

[Искл.]

После второго изменения содержимого поля

row.BeginEdit();

row["id"] = 300;

row.EndEdit();

300

1

[Искл.]

После отмены изменений

row.BeginEdit();

row["id"] = 500;

row.CancelEdit()

300

1

[Искл.]

После удаления записи

DataRow row = Artists.Rows[0];

row.Delete();

[Искл.]

1

[Искл.]

Для контроля существования версии строки можно использовать метод HasVersion():

if (row.HasVersion(DataRowVersion.Current))

{

Console.WriteLine("Current version exists");

}

Любая строка предоставляет методы AcceptChanges() и RejectChanges(). Вызов первого метода закрепляет в строке все отложенные изменения, а вызов второго – отбрасывает отложенные изменения. Иными словами, вызов AcceptChanges() приводит к замене значений Original-версии строки значениями из Current-версии и установке у строки RowState=Unchanged. Вызов RejectChanges() устанавливает RowState=Unchanged, но значения Current-версии строки меняются на значения Original-версии. При загрузке изменений DataSet в базу у каждой строки неявно вызывается метод AcceptChanges(). Внимание: явное использование указанных методов может породить проблемы при синхронизации набора данных и базы.

С помощью методов SetAdded() и SetModified() свойство RowState строки может быть изменено программно. Использование этих методов приводит к принудительному обновлению данных при передаче изменений в базу, даже если сами данные не претерпели изменений.