Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции OOP c#.doc
Скачиваний:
44
Добавлен:
22.09.2019
Размер:
3.38 Mб
Скачать

4.13. Типизированные DataSet

В обычных объектах DataSet для доступа к отдельным элементам используются индексированные коллекции. Недостатком такого подхода является отсутствие контроля правильности имен таблиц и столбцов во время компиляции.

Платформа .NET поддерживает типизированные наборы данных. Типизированный набор данных – это класс, который является наследником класса DataSet. В отличие от DataSet, в типизированном наборе для доступа к отдельным компонентам служат свойства. Имя свойства – это имя элемента DataSet (например, имя таблицы), тип свойства – класс-наследник стандартного класса из DataSet.

Создать типизированный DataSet можно несколькими способами. В Visual Studio для этого используется специальный мастер (wizard). В состав .NET Framework SDK входит утилита xsd.exe, формирующая типизированные наборы данных на основании XSD-файла со схемой набора.

Разберем пример использования xsd.exe. Пусть есть набор данных со схемой, построенной в предыдущем параграфе и сохраненной в файле schema.xsd. Выполним команду1:

C:\TMP>xsd schema.xsd /d

В результате получим файл schema.cs, фрагмент которого приведен ниже:

using System;

using System.Data;

using System.Xml;

using System.Runtime.Serialization;

public class CD_Rent_Part : DataSet {

private ArtistsDataTable tableArtists;

private DisksDataTable tableDisks;

private DataRelation relationArtists_to_Disks;

public CD_Rent_Part() {. . .}

public ArtistsDataTable Artists {

get {

return this.tableArtists;

}

}

public DisksDataTable Disks {

get {

return this.tableDisks;

}

}

public override DataSet Clone() {

CD_Rent_Part cln = ((CD_Rent_Part)(base.Clone()));

cln.InitVars();

return cln;

}

public class ArtistsDataTable: DataTable,IEnumerable {...}

public class ArtistsRow : DataRow {. . .}

public class DisksDataTable : DataTable, IEnumerable {...}

public class DisksRow : DataRow {. . .}

}

Используя файл schema.cs и класс CD_Rent_Part, работать с набором данных можно следующим образом. Вместо кода, подобного следующему,

string s = (string) CD_Rent.Tables["Artists"].Rows[0]["name"];

можно писать такой код:

CD_Rent_Part cd = new CD_Rent_Part();

string s1 = cd.Artists[0].name;

Обратите внимание:

  1. Таблица представлена свойством Artists (типа ArtistsDataTable).

  2. Для доступа к определенной строке таблицы используется индексатор, примененный к свойству Artists.

  3. Тип строки – ArtistsRow. Это позволяет обратиться к полю строки как к свойству и не выполнять приведение типов.

Подытожим: типизированные DataSet позволяют установить контроль правильности кода во время компиляции. Это способно упростить разработку приложений и сделать использование типов более безопасным.

4.14. Поиск и фильтрация данных в DataSet

В примерах данного параграфа предполагается, что имеется DataSet с заданной схемой (см. параграф 12), и в этот набор данных загружены две таблицы из базы CD_Rent:

SqlDataAdapter da = new SqlDataAdapter(

"SELECT * FROM Artists",

"Server=(local);Database=CD_Rent;" +

"Integrated Security=SSPI");

da.MissingSchemaAction = MissingSchemaAction.Error;

da.Fill(CD_Rent, "Artists");

da.SelectCommand.CommandText = "SELECT * FROM Disks";

da.Fill(CD_Rent, "Disks");

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

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

foreach (DataRow row in Artists.Rows) {

Console.WriteLine(row["name"]);

DataRow[] childRows =

row.GetChildRows("Artists_to_Disks");

foreach (DataRow r in childRows)

Console.WriteLine("\t" + r["title"]);

}

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

foreach(DataRow row in Disks.Rows) {

Console.Write(row["title"]);

DataRow parentRow = row.GetParentRow("Artists_to_Disks");

Console.WriteLine("" + parentRow["name"]);

}

Метод GetParentRows() возвращает все родительские строки определенной строки. Данный метод имеет смысл использовать, если задана такая связь, при которой колонка родительской таблицы не является первичным ключом (не уникальна).

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

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

Метод Find(), который предоставляет класс DataRowCollection ищет строки таблицы с определенным значением первичного ключа. Метод Find() принимает как параметр значение первичного ключа искомой строки. Поскольку значения первичного ключа уникальны, метод вернет не более одного объекта DataRow. Следующий фрагмент кода ищет данные в таблице Artists:

// В Artists определен первичный ключ.

// Find() принимает как параметр объект

// и сам приводит его к нужному типу

DataRow row = Artists.Rows.Find(1);

if (row != null) Console.WriteLine(row["name"]);

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

Метод Select() класса DataTable позволяет искать ряды по определенному критерию. В простейшем случае методу передается строка, описывающая критерий поиска. Метод возвращает массив найденных строк. В следующем примере из таблицы Disks выбираются все диски, записанные в 2006 году:

DataRow[] result = Disks.Select("release_year = 2006");

foreach (DataRow row in result)

Console.WriteLine(row["title"]);

Несколько слов о построении строки-критерия. Строка может содержать слово LIKE, которое осуществляет поиск по частичному совпадению. В этом случае используется шаблон, содержащий метасимволы * или % для обозначения начальной или конечной части строки. Например, осуществим поиск всех дисков, название которых начинается с "U":

DataRow[] result = Disks.Select("title LIKE 'U*'");

Иногда требуется заключить в символы-разделители имена столбцов, используемые в критерии поиска. Например, когда имя содержит пробел или другой символ, не относящийся к алфавитно-цифровым, или похоже на зарезервированное слово типа LIKE или SUM. Так, если имя столбца – Space In Name и требуется выбрать все строки, значение поля Space In Name которых равно 3, воспользуйтесь следующим критерием поиска:

strCriteria = "[Space In Name] = 3"

Если имя столбца включает символ-разделитель, поставьте в критерии поиска перед закрывающим символом-разделителем (]) управляющий символ (\). Например, если имя столбца – Bad]Column[Name и требуется выбрать все строки, у которых значение этого поля равно 5, используйте такую строку поиска:

strCriteria = @"[Bad\]Colunin[Name] = 5";

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

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

DataRow[] result = Disks.Select("release_year = 2005", "title DESC");

Если надо выполнить поиск только в измененных строках таблицы, воспользуйтесь перегруженным методом Select() и укажите значение из перечисления DataViewRowState. Можно считать, что это значение – фильтр, добавленный в критерий поиска. Предположим, требуется просмотреть только измененные и удаленные записи таблицы. Воспользуемся константами ModifiedOriginal и Deleted из перечисления DataViewRowState и укажем в качестве параметров фильтрации и сортировки пустые строки:

DataRow[] result = Disks.Select("", "",

DataViewRowState.ModifiedOriginal |

DataViewRowState.Deleted);