Связанные таблицы
Задача темы: изучить методику и получить навыки использования связей между таблицами в реляционных хранилищах данных
Разработка: Приложение "DataRelation" для оценки скорости выполнения запросов в связанных таблицах
Состав выполняемых функций:
- Файловые операции: автоматическое открытие и загрузка данных из двух файлов
- Алгоритмы: выборка данных из одного файла и добавление их в другой; оценка скорости выполнения запроса
- Информационно-справочные: О программе
Наращивание функциональности не предусматривается.
Защита данных – нет.
В качестве входных данных используется XML – файл Mersedes.xml с записями о периодах проведения регламентных работ и структурой, состоящей из полей: <Деталь>; <Цена>; <Фирма>; <Дата>; <Группа>; <О_ фирме>; <Услуга>; <Об _услуге>; <Пробег>; <ID> (фрагмент файла показан на рис.14.1).
Выходные данные программы:
- XML – файл test_norm.xml с выборкой записей из файла Mersedes.xml о фактическом пробеге в момент проведения регламентных работ и структурой, состоящей из полей: <Деталь>; <Норма пробега>; <Фактический пробег>; <ID>. Выходной файл содержит несколько записей с заполненными полями, значение фактического пробега в поле <Фактический пробег> равно 0 – это поле будет заполнено в результате выполнения запроса. Полем связи таблиц является поле <Деталь>;
- графическое отображение результатов результата выполнения запроса в DataGrid файла test_norm.xml и скорости выполнения запроса в текстовых полях формы для SmartDevice.
Шаг 1. Организапция дискового пространства
В каталоге \bin\debug размещаем оба файла – Mersedes.xml и test_norm.xml
Шаг 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, "Готово"); }14.1.
Шаг 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", "О программе"); }