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

Довольно часто некоторые поля данных надо скрыть, не отображать их на форме (например, поля первичных автоинкрементируемых ключей). Для этого просто не включайте эти поля в множество колонок (объектов DataGridViewTextBoxColumn), которое добавляется в DataGridView (studsGrid.Columns.Add(tb);).

Запись и чтение данных

Класс DataSet значительно упрощает операции записи и чтения данных. Он имеет множество встроенных свойств и методов, поддерживающих управление данными в формате XML. Начнем с метода записи данных.

void Save(string file)

{

  if (file == null || ds.Tables[0].Rows.Count == 0)

    return;

  ds.WriteXml(file);

  fileName = file;

}

Имя файла получим от пользователя с помощью метода FileDlg.

  string FileDlg(bool bOpen)

  {

    FileDialog dlg = bOpen ? (FileDialog)new OpenFileDialog()

      : (FileDialog)new SaveFileDialog();

    dlg.InitialDirectory = Application.StartupPath + "\\..\\..";

    dlg.Filter = "People files (*.xml)|*.xml";

    dlg.Title = "Select data file to " + (bOpen ? "open" : "save");

    dlg.FileName = fileName;

    return dlg.ShowDialog() == DialogResult.OK ? dlg.FileName : null;

  }

Чтение всего набора данных из XML-файла выполним в методе Open. Для обеспечения видимости новых классов попросите студию вставить недостающие директивы using.

  void Open(string file)

  {

    if (file == null)

      return;

    ds.Clear();

    ds.ReadXml(file);

    fileName = file;

   Text = "Students Table: " + file.Substring(file.LastIndexOf('\\') + 1);

}

Отметьте, что при чтении набора данных (DataSet) из файла он рождается заново, поэтому старые данные необходимо уничтожить (см. вызов метода Clear). Запустите приложение и сохраните данные в произвольном файле папки проекта. Теперь можно закомментировать строку вызова InitTables и проверить поведение приложения при начальном открытии файла с данными.

Отображение данных связанной таблицы

Связь (relationship) между первой таблицей Studs и второй — Exams имеет вид один ко многим. В реальной базе данных это, как вы знаете, означает, что первичные ключи первой таблицы неоднократно скопированы во вторую и эти копии носят имя связанных ключей (foreign keys). Они ссылаются на строки главной, первичной таблицы, образуя ссылочную целостность данных (referential integrity: каждый экзамен принадлежит какому-то студенту).

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

Следующий фрагмент надо добавить в метод InitDataSet (после кода, который помещает таблицы в DataSet).

DataRelation dr = new DataRelation("StudExam",

  studs.Columns["ID"], exams.Columns["StudID"]);

ds.Relations.Add(dr);

Здесь мы создаем объект класса DataRelation и помещаем его в коллекцию Relations объекта DataSet. Этого кода достаточно для синхронизации отображения данных связанных таблиц. Суть синхронизации в том, что мы показываем не все экзамены, а только экзамены студента, активного (выбранного) в первой таблице. С этой задачей справится механизм DataBinding, которому надо дать ссылку на DataRelation.

Но если мы хотим не только просматривать данные, но и вносить изменения, то для сохранения целостности по ссылкам, необходимо добавить код, создающий объект класса ForeignKeyConstraint. Он задает ограничение, накладываемое на данные обеих таблиц. Ограничение (constraint) типа FK-PK (ForeignKey-PrimaryKey) следит за тем, чтобы не нарушалась целостность данных по ссылкам.

Ограничения, в отличие от связей, попадают в коллекцию ограничений таблицы, а не в DataSet. Каждый объект класса DataTable имеет список ограничений, накладываемых на ее столбцы. Имея представление о том, как устроена библиотека классов .NET Framework, нетрудно догадаться, что этот список представляет собой коллекцию объектов какого-то специального класса.