Введение в ADO.NET. Источник данных - XML-файл. Отображение данных связанной таблицы, страница 10

В множество колонок объекта DataTable легко добавить вычисляемые колонки, то есть, поля данных, которых в действительности в источнике данных нет, но они вычисляются и добавляются в таблицу на ходу. Это, в частности,  можно сделать с помощью объекта DataRelation. Каждый студент сдал какие-то экзамены и они хранятся в связанной таблице Exams. Их количество может отличаться (если нет, то вы сделаете его разным, работая с формой и XML-файлом данных). С помощью объекта DataRelation мы вычислим количество экзаменов для каждого студента и покажем его в отдельной колонке таблицы DataTable, а, следовательно, (благодаря механизму DataBinding) и DataGridView. Добавим в таблицу студентов колонку, отображающую количество сданных ими экзаменов. Это делается удивительно просто.

ds.Tables[0].Columns.Add("ExamsNo", typeof(int), "Count(Child.StudID)");

Эту строку кода следует вставить после того, как в DataSet была добавлена связь между таблицами студентов и экзаменов, но до вызова метода AddStyleStud (иначе наш стиль не подействует на новую колонку). Секрет ее работы состоит в строковой константе "Count(Child.StudID)" (вспомните про роль имен в механизме DataBinding). Она задает значение свойства Expression (вычисляемое выражение), которое имеется в каждом объекте класса DataColumn. Рассмотрим части выражения.

¨  Count() определяет функцию SQL-запроса,

¨  Child определяет множество строк, таблицы Exams, связанных с текущей строкой таблицы студентов,

¨  StudID определяет поле внешнего ключа связи.

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

¨  Вместо метода WriteXml класса DataSet использовать метод Serialize класса XmlSerializer.

¨  Для этого придется ввести промежуточный слой: сериализуемые классы Stud и Exam или класс MyDataTable, производный от DataTable.

¨  В промежуточном слое надо пометить исключаемое свойство атрибутом [XmlIgnore], или не иметь его вовсе.

¨  Сериализовывать можно или видоизмененный DataSet, или вспомогательные коллекции, содержащие объекты классов Stud и Exam.

Задание. Добавьте колонку, которая вычисляет средний балл студента.

ds.Tables[0].Columns.Add("Average", typeof(decimal), "Sum(Child.Mark)/Count(Child.StudID)");

Поиск в таблице DataTable и в компоненте DataGridView

Отображение данных в DataGridView и манипуляция данными в DataSet — это две разные функции. DataGridView обеспечивает интерфейс пользователя, а архитектура привязки к данным (data-binding architecture) ADO.NET отслеживает изменение данных в памяти. При этом важно, чтобы изменения данных в DataGridView были всегда синхронизированы с их изменениями в DataSet.

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

public DataRow[] Select(

   string filterExpression, // Критерий фильтрации содержимого

   string sort,            // Способ сортировки

   DataViewRowState recordStates); // Критерий фильтрации состояния строк

Как видите, он возвращает ссылку на генерируемый на ходу массив строк, которые удовлетворяют критерию поиска. Параметры имет следующий смысл:

¨  filterExpression — выражение, определяющее что следует искать. Оно фильтрует записи, отбрасывая те, что не удовлетворяют критерию поиска. Формат выражения сходен с оператором  WHERE языка SQL.

¨  sort — строка текста указывающая, как сортировать найденные записи. Ее формат совпадает с тем, что используется  оператором  ORDER BY выражения SQL.