Базы данных для карманного персонального компьютера

Связанные таблицы

Показывать лекцию целиком

Задача темы: изучить методику и получить навыки использования связей между таблицами в реляционных хранилищах данных

Разработка: Приложение "DataRelation" для оценки скорости выполнения запросов в связанных таблицах

Состав выполняемых функций:

  • Файловые операции: автоматическое открытие и загрузка данных из двух файлов
  • Алгоритмы: выборка данных из одного файла и добавление их в другой; оценка скорости выполнения запроса
  • Информационно-справочные: О программе
  • Наращивание функциональности не предусматривается.

    Защита данных – нет.

    В качестве входных данных используется XML – файл Mersedes.xml с записями о периодах проведения регламентных работ и структурой, состоящей из полей: <Деталь>; <Цена>; <Фирма>; <Дата>; <Группа>; <О_ фирме>; <Услуга>; <Об _услуге>; <Пробег>; <ID> (фрагмент файла показан на рис.14.1).

    Выходные данные программы:

  • XML – файл test_norm.xml с выборкой записей из файла Mersedes.xml о фактическом пробеге в момент проведения регламентных работ и структурой, состоящей из полей: <Деталь>; <Норма пробега>; <Фактический пробег>; <ID>. Выходной файл содержит несколько записей с заполненными полями, значение фактического пробега в поле <Фактический пробег> равно 0 – это поле будет заполнено в результате выполнения запроса. Полем связи таблиц является поле <Деталь>;
  • графическое отображение результатов результата выполнения запроса в DataGrid файла test_norm.xml и скорости выполнения запроса в текстовых полях формы для SmartDevice.
  • (рис 14.1)

    Шаг 1. Организапция дискового пространства

    В каталоге \bin\debug размещаем оба файла – Mersedes.xml и test_norm.xml

    Шаг 2. Организация графического интерфейса

    (рис 14.2)

    Одна форма с кнопкой "Обновить связь", элементом DataGrid для вывода данных файла test_norm.xml, двумя надписями "Т обособленных таблиц" и "Т связанных таблиц", двумя полями для вывода результатов запроса к связанным таблицам и для вывода выборки из данных Mersedes.xml по ключу таблицы test_norm.xml. Примерный дизайн показан на рис.14.2

    Из не видимых элементов – главное меню с опцией "О программе".

    Шаг 3. Добавляем библиотеки

    using System;
    using System.Drawing;
    using System.Collections;
    using System.Windows.Forms;
    using System.Data;
    //добавляем 
    using System.IO;
    using System.Xml;
    using System.Runtime;

    Шаг 4. Определяем переменные в public class Form1 : System.Windows.Forms.Form

    // организуем доступ (public static) из других классов (необязательно)
    public static string file_name=@"\Mersedes.xml"; // пробег деталей
    public static string file_norm=@"\test_norm.xml"; // нормы пробега
    // глобальный датасет - объекты, содержащие ссылки на таблицы 
    public static DataSet dataSetApp, dataSet, dataSet1; 
    //глобальный дататейбл - таблицы
    public static DataTable dataTableApp, dataTable, dataTable1 ;

    Шаг 5. Дополняем процедуру загрузки формы public Form1()

    { // Required for Windows Form Designer support
    InitializeComponent();
    //создаем один объект для 2-х таблиц, иначе связь невозможна
    dataSetApp=new DataSet();	
    dataTableApp=dataSetApp.Tables.Add("Нормы");//1-я таблица в dataSetApp
    // добавляем столбцы
    dataTableApp.Columns.Add("Деталь",System.Type.GetType("System.String"));
    dataTableApp.Columns.Add("Норма",System.Type.GetType("System.String"));
    dataTableApp.Columns.Add("Факт",System.Type.GetType("System.String"));
    dataTableApp.Columns.Add("ID",System.Type.GetType("System.Int64"));
    // вторая таблица в dataSetApp			
    dataTable1=dataSetApp.Tables.Add("Пробег замененных частей");	
    // добавляем столбцы
    dataTable1.Columns.Add("Деталь", 
    System.Type.GetType("System.String")).MaxLength=100;
    dataTable1.Columns.Add("Пробег", 
    System.Type.GetType("System.String")).MaxLength=10;
    dataTable1.Columns.Add("Дата", 
    System.Type.GetType("System.String")).MaxLength=10;
    // пытаемся прочитать файл
    FileStream fin;		
    try {
    fin=new FileStream(file_norm,FileMode.Open);
    fin.Close();
    // Считываем значения из файла
    XmlTextReader xml_in=new XmlTextReader(file_norm); 
    dataSetApp.ReadXml(@xml_in);
    xml_in.Close();
    	}
    catch(IOException exc) {
    MessageBox.Show("Нет файла с нормами пробега \n"+file_norm,
    "Ошибка открытия файла");
    return;}
    // программируем стиль грида, сортируем и привязываем данные файла норм
    this.dataGrid1.TableStyles.Clear();
    DataGridTableStyle tsApp= new DataGridTableStyle();
    tsApp.MappingName="Нормы";
    DataGridTextBoxColumn csApp=new DataGridTextBoxColumn();
    csApp.Width=104;
    csApp.MappingName="Деталь";
    csApp.HeaderText="Деталь";
    tsApp.GridColumnStyles.Add(csApp);
    
    csApp = new DataGridTextBoxColumn();
    csApp.Width=44;
    csApp.MappingName="Норма";
    csApp.HeaderText="Норма";
    tsApp.GridColumnStyles.Add(csApp);
    			
    csApp = new DataGridTextBoxColumn();
    csApp.Width=54;
    csApp.MappingName="Факт";
    csApp.HeaderText="Остаток";
    tsApp.GridColumnStyles.Add(csApp);
    
    csApp = new DataGridTextBoxColumn();
    csApp.Width=50;
    csApp.MappingName="ID";
    csApp.HeaderText="ID";
    tsApp.GridColumnStyles.Add(csApp);
    				
    this.dataGrid1.TableStyles.Add(tsApp);
    DataView sortedView=new DataView(dataTableApp);
    sortedView.Sort="Норма, Деталь";//  сортировка	
    dataGrid1.DataSource=sortedView;// привязываем
    }

    Шаг 6. Создаем процедуру инициации запроса

    Для кнопки "Обновить данные" пишем:

    private void button1_Click(object sender, System.EventArgs e) {
    FileStream fin;		
    try {
    fin=new FileStream(file_name,FileMode.Open);
    fin.Close();
    	}
    catch(IOException exc) {
    MessageBox.Show ("Невозможно открыть файл \n"+file_name,"Ошибка");
    return;}
    // Считываем значения из файла
    XmlTextReader xml_in=new XmlTextReader(file_name); 
    dataSet=new DataSet();
    //Грузим данные из таблицы DataTable 
    dataTable=dataSet.Tables.Add("Моя_Гну");
    dataTable.Columns.Add("Деталь",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Цена",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Фирма",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Дата",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Группа",System.Type.GetType("System.String"));
    dataTable.Columns.Add("О фирме",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Услуга",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Об услуге",System.Type.GetType("System.String"));
    dataTable.Columns.Add("Пробег",System.Type.GetType("System.String"));
    dataTable.Columns.Add("ID",System.Type.GetType("System.Int64"));
    dataSet.ReadXml(@xml_in);
    xml_in.Close();
    // добавляем первую строку для шаблона
    int my_test=0;
    int my_maxpath=0;
    int my_maxpath_up=0;
    int my_maxpath_down=0;
    string my_date="err";
    string my_path="err";
    string my_fuel, my_service;
    foreach (DataRow row0 in dataTable.Rows) {
    //вычисляем максимальный пробег	
    my_maxpath_up=int.Parse(row0["Пробег"].ToString());			
    if (my_maxpath<=my_maxpath_up)
    my_maxpath=my_maxpath_up;
    	}
    my_maxpath_up=0;// обнуляем для выборки в группе
    foreach (DataRow row in dataTable.Rows) {//cicle
    my_fuel=(row["Деталь"].ToString());
    // фильтруем с сортировкой
    DataRow[] my_rows=dataTable.Select("Деталь='"+my_fuel+"'");	
    foreach (DataRow row2 in my_rows ){
    // вычисляем максимальный пробег детали
    my_maxpath_up=int.Parse(row2["Пробег"].ToString());				
    if (my_maxpath_down<=my_maxpath_up) {
    my_maxpath_down=my_maxpath_up;
    my_path=(my_maxpath-my_maxpath_down).ToString();
    my_date=(row2["Дата"].ToString());
    }
    		}
    my_maxpath_up=0;// обнуляем для выборки в группе
    my_maxpath_down=0;// обнуляем для выборки в группе
    my_test=0;
    // проверяем группу в новой таблице по самому большому ID
    foreach (DataRow row1 in dataTable1.Rows){
    my_service=(row1["Деталь"].ToString());
    if (my_fuel==my_service)
    my_test=1;
    		}
    if (my_test==0){
    object[] a1={my_fuel,my_path,my_date};
    dataTable1.Rows.Add(a1);
    		}
    	}
    /* устанавливаем связь между таблицами dataTableApp и dataTable1:
    Объект главной таблицы - имя связи - поле связи в главной - поле 
    связи в связанной таблице. Главная таблица та - в которой больше 
    записей, а не наоборот, в противном случае генерируется исключение, 
    что не хватает записей
    */
    DataColumn[]{dataTableApp.Columns["Деталь"]};// в таблице "Нормы"
    DataColumn[]{dataTable1.Columns["Деталь"]};//"Пробег замененных частей"
    // тестируем варианты 
    DateTime time_start;
    DateTime time_finish;
    if (MessageBox.Show("Выбираем данные из обособленных (Да) 
    или связанных (Нет)таблиц?", "Тестируем 
    варианты", MessageBoxButtons.YesNo, 
    	MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) = 
    =  DialogResult.Yes) {// выборка по ключу
    // считываем значения из таблицы норм
    time_start=DateTime.Now;
    foreach (DataRow row0 in dataTableApp.Rows) {
    my_fuel=(row0["Деталь"].ToString());
    my_maxpath=int.Parse(row0["Норма"].ToString());
    foreach (DataRow row1 in dataTable1.Rows) {
    my_service=(row1["Деталь"].ToString());
    //вычисляем максимальный пробег
    my_maxpath_up=int.Parse(row1["Пробег"].ToString());			
    if (my_fuel==my_service)
    my_maxpath=my_maxpath-my_maxpath_up;
    			}
    if (my_maxpath>=int.Parse(row0["Норма"].ToString()))
    row0[2]="Заменить";
    else
    row0[2]=my_maxpath.ToString();	
    		}
    time_finish=DateTime.Now;
    this.textBox1.Text=(time_finish-time_start).ToString();
    	}
    else{ // вариант запроса к  связанным таблицам
    time_start=DateTime.Now;
    dataSetApp.Relations.Add("Set_My_Relation", 
    dataTable1.Columns["Деталь"], dataTableApp.Columns["Деталь"], true);
    for (int i=0; i<dataTable1.Rows.Count; i++) {
    //вычисляем пробег
    my_maxpath_up=int.Parse(dataTable1.Rows[i]["Пробег"].ToString());
    // считываем значения из таблицы норм
    foreach (DataRow row0 
    in dataTable1.Rows[i].GetChildRows("Set_My_Relation")) {
    my_fuel=(row0["Деталь"].ToString());
    my_maxpath=int.Parse(row0["Норма"].ToString());
    my_maxpath=my_maxpath-my_maxpath_up;
    if (my_maxpath>=int.Parse(row0["Норма"].ToString()))
    row0[2]="Заменить";
    else
    row0[2]=my_maxpath.ToString();	
    			}
    		}
    dataSetApp.Relations.Remove("Set_My_Relation");// разрываем связь
    time_finish=DateTime.Now;
    this.textBox2.Text=(time_finish-time_start).ToString();	
    	}
    time_finish=DateTime.Now;
    MessageBox.Show("Загружены данные из файла \n"+file_name, "Готово");
    }

    Шаг 7. Создаем процедуру просмотра строк DataGrid

    private void dataGrid1_Click(object sender, System.EventArgs e) {
    int N_row=dataGrid1.CurrentCell.RowNumber;
    MessageBox.Show(// вывод значения ячейки
    	dataGrid1[N_row,0].ToString()+"\n"+
    	dataGrid1[N_row,1].ToString()+"\n"+
    	dataGrid1[N_row,2].ToString(),dataGrid1[N_row,3].ToString());
    }

    Шаг 8. Создаем процедурку "О программе"

    Для опции главного меню "О программе" пишем:

    private void menuItem1_Click(object sender, System.EventArgs e) {
    MessageBox.Show("Проблема:\n"+"Есть 2 XML-файла,из одного нужно 
    выбрать данные и ввести их в другой.\n"+ "Решение:\n"+"Выборка 
    перебором записей по условию в таблицу DataTable1,\n"+"связанной 
    с таблицей DataTableApp в которой заполняются вычисляемые 
    поля.\n"+"(C)Родигин Л.А., ноябрь 2006, платформа C# Visual 
    Studio 2003", "О программе");		
    }
    Вернуться к учебному плану