Файл: Справочник для опытных и как пособие для начинающих программистов. Компактдиск содержит исходные коды примеров из книги.doc
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.01.2024
Просмотров: 948
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
XML, см. листинг 11.8) найти все строчки с именем "Витя". Эта маленькая несерьезная, на первый взгляд, задача подразумевает, например, такую уже "серьезную" задачу. Имеем громадную базу данных, которую мы получили на каком-то этапе обработки в виде XML, и нам требуется "отфильтровать" записи в этой базе на предмет содержания в некотором поле определенной строки.
Прежде чем решать данную задачу, давайте посмотрим отображение обсуждаемых XML-данных в табличном редакторе MS Excel (рис. 11.11).
Рис. 11.11. Отображение XML-данных в MS Excel
Как видно, в редакторе MS Excel наши XML-данные представлены весьма наглядно. И очень понятно, что мы хотим получить, а именно, все номера телефонов напротив имени "Витя".
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — Linq5. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим текстовое поле TextBoх для вывода в него найденных строк из таблицы XML. В свойствах текстового поля разрешим ввод множества строк (а не одной), для этого свойство Multiline переедем в состояние true. Затем на вкладке программного кода введем текст, представленный в листинге 11.8.
Листинг 11.8. Извлечение значения элемента из XML-данных
//Имеем XML-данные, в которых содержится таблица с именами и телефонами,
// причем имена в этой телефонной табличке повторяются. Задача состоит в том,
// чтобы в данной таблице телефонов (представленной в виде XML) найти все
// строчки с именем "Витя" с помощью LINQ-запроса
using System.Linq;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace Linq5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Text = "LINQ-запрос к XML-данным"; textBox1.Multiline = true;
// Инициализация XML-строки:
string CтрокaXML =
@"
<ТаблицаТелефонов> <Строка>
<Имена>ВитяИмена>
<Номера_телефонов>274 28 44Номера_телефонов>
Строка>
<Строка>
<Имена>АндрейИмена>
<Номера_телефонов> 8-085-45б-2378Номера_телефонов>
Строка>
<Строка>
<Имена>Карапузова ТаняИмена>
<Номера_телефонов>4 45-56-47Номера_телефонов>
<Строка>
<Имена>ВитяИмена>
<Номера_телефонов>099 72 161 52Номера_телефонов>
Строка>
<Строка>
<Имена>НикипеловИмена>
<Номера_телефонов>2 3 6-77-7 6Номера_телефонов>
Строка>
<Строка>
<Имена>ЗиборовИмена>
<Номера_телефонов>254 67 97Номера_телефонов>
Строка>
ТаблицаТелефонов>";
var КорневойЭлемент = System.Xml.Linq.XElement.Parse(CтрoкaXML);
// Запись строки, содержащей XML, в, файл:
// System.IO.File.WriteAllText("ТаблицаТелефонов.xml", CтрокaXML);
// var КорневойЭлемент = System.Xml.Linq.
// XElement.Load("ТаблицаТелефонов.xml");
var Записи = from x in КорневойЭлемент.Elements("Строка")
where (string)x.Element("Именa") == "Витя"
select x.Element ("Номера_телефонов") .Value;
textBox1.Text = textBox1.Text + @"Строки, содержащие имя ""Витя"":" + "\r\n";
// Вывод коллекции записей в текстовое поле textBox1:
foreach (var х in Записи)
textBox1.Text = textBox1.Text + x + "\r\n";
// Таких записей в этой коллекции - ровно одна
}
}
}
Как видно, в начале программы мы инициализируем (т.е. присваиваем начальные значения) XML-строку. Далее извлекаем корневой элемент из XML-документа, oн, по сути, отличается от XML-документа отсутствием XML-объявления (в этом можно убедиться в отладчике программы). В комментарии указано, как можно получить корневой элемент в том случае, если он представлен в виде XML-файла во внешней памяти. Затем организуем типовой, стандартный LINQ-запрос. Результат запроса попадает в коллекцию записей, которую выводим в текстовое поле, используя оператор цикла foreach. Фрагмент работы программы показан на рис. 11.12.
Убедиться в работоспособности программы можно, открыв решение Linq5.sln из папки Linq5.
Рис. 11.12. LINQ-запрос к XML-документу
Пример 82. LINQ-запрос к набору данных DataSet
Весьма полезной оказывается организация LINQ-запросов к наборам данных DataSet, используемым, к примеру, при работе с базами данных. Объект класса DataSet представляет расположенный в памяти кэш (cache) данных (кэш — это промежуточная память с быстрым доступом, содержащая информацию, которая может быть запрошена с наибольшей вероятностью). Реляционные базы данных работают чаще всего с совокупностью таблиц. Каждая из этих таблиц задается как объект класса DataTable, один такой объект представляет ровно одну таблицу данных. Набор данных DataSet содержит в себе несколько объектов (таблиц) DataTable. Запросы LINQ к таблицам данных, кэшированным в объекте
DataSet, упрощают и ускоряют процесс отбора.
Данная задача состоит в том, чтобы создать программу, которая обеспечивает ввод простейшей таблицы, содержащей два поля — название города и численное его населения. Программа способна фильтровать данные в таблице; будем производить отбор городов, численность населения которых превышает миллион жителей.
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqГopoдa. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим элемент управления для отображения и редактирования табличных данных DataGridView, две командные кнопки Button и текстовое поле TextBox. Одна кнопка предназначена для команды сохранения данных, другая — для поиска данных в таблице, а текстовое поле — для вывода в него найденных строк из таблицы. В свойствах текстового поля разрешим ввод множества строк, для этого свойство Multiline переведем в состояние truе. Затем на вкладке программного кода введем текст, представленный в листинге 11.9. I
Листинг 11.9. Извлечение полей из набора данных DataSet
//В данной программе экранная форма содержит элемент управления
// для отображения и редактирования табличных данных DataGridView,
// две командные кнопки и текстовое поле. При старте программы,
// если есть соответствующий файл XML, программа отображает
//в DataGridView таблицу городов - название города и численность населения.
// При щелчке на кнопке "Сохранить" все изменения в таблице записываются
// в XML-файл. При щелчке на второй кнопке "Найти" выполняется LINQ-запрос
// к набору данных DataSet на поиск городов-миллионеров в искомой таблице.
//Pезультат запроса выводится в текстовое поле.
using System;
using System.Data;
usingSystem.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace _LinqГopoдa
{
public partial class Form1 : Form
{
DataTable Таблица = new DataTabie(); // Создание объекта "таблица данных"
DataSet НаборДанных = new DataSetО; // Создание объекта "набор данных"
public Form1()
{
InitializeComponent();
base.Text = "LINQ-запрос к набору данных DataSet";
button1.Text = "Сохранить"; button2.Text = "Найти";
textBox1.Multiline = true;
if (System.IO.File.Exists("Города.xml") == false)
{ // Если XML-файла НЕТ:
// заполнение "шапки" таблицы
Таблица.Columns . Add ("Город") ; Таблица. Columns . Add ("Население");
// Добавить объект Таблица в DataSet:
НаборДанных.Таbles.Add(Таблица);
dataGridView1.DataSource = Таблица;
}
else // Если XML-файл ЕСТЬ:
{
НаборДанных. ReadXml (" Города. xml");
// Содержимое DataSet в виде строки XML для отладки:
// string CтрокaXML = НаборДанных.GetXml();
Таблица = НаборДанных.Tables["Города"];
dataGridView1.DataMember = "Города";
dataGridView1.DataSource = НаборДанных;
}
}
private void button1_Click(object sender, EventArgs e)
{ // Щелчок мышью на кнопке "Сохранить" - сохранить файл Города.xml:
Таблица.TableName = "Города";
НаборДанных.WriteXml("Города.xml");
}
private void button2_Click(object sender, EventArgs e)
{ // Щелчок мышью на кнопке "Поиск" - запрос городов-миллионеров:
textBoxl.Clear(); // - очистка текстового поля
var ГородаМлн = from Город in Таблица.AsEnumerable()
where Convert.ToInt32(Город.
Field("Население")) >= 1000000
select new
{
A = Город.Field("Город"),
В = Город.Field("Население")
};
textBox1. Text = textBox1. Text + "Города-миллионеры: \r\n";
// Вывод результата запроса в текстовое поле textBox1:
foreach (var Город in ГородаМлн) textBox1.Text = textBox1.Text +
Город.A + " - " + Город.В + "\r\n";
}
}
}
В начале программы создаем объекты классов DataSet и DataTable так, чтобы они были видимыми из всех процедур класса Form1. Далее сразу после инициализации компонентов экранной формы (т. е. после выполнения процедуры InitializeComponent) проверяем, существует ли файл Города.хml, куда мы записываем искомую таблицу. Если файл не существует, т. е. пользователь первый раз запустил нашу программу, то мы создаем таблицу, состоящую из двух полей (колонок): "Город" и "Население", добавляем (Add) эту таблицу в набор данных , а также указываем таблицу в качестве источника данных (DataSource) для сеянных dataGridView1. Если же файл Города.xml уже создан, то мы читаем егo в набор данных DataSet и из него заполняем таблицу данных, а также этот набор данных указываем в качестве источника для сетки данных.
При обработке события "щелчок мышью на кнопке" Запись программируем сохранение редактируемой таблицы в файле Города.хml. В процедуре обработки события "щелчок на кнопке" Найти организуем LINQ-запрос к заполненной пользователем таблице DataTable, являющейся представителем DataSet. Условием запроса является отбор таких полей таблицы, где население превышает миллион жителей. Заметим, что если не задавать условие where, то в результате запроса получим все содержимое источника данных, т. е. все строки таблицы городов. Результат запроса выводим в текстовое поле, используя цикл foreach.
Фрагмент работы программы показан на рис. 11.13.
Убедиться в работоспособности программы можно, открыв решение LinqГopoдa.sln из папки LinqГopoдa.
Рис. 11.13. LINQ-запрос к набору данных
Пример 83. Доступ к базе данных с помощью LINQ to SQL
В данном примере вначале создадим базу данных городов, содержащую два поля: название города и численность его населения. Затем организуем доступ к этой базе данных с помощью LINQ to SQL и создадим запрос на извлечение коллекции городов, численность населения в которых превышает миллион жителей. Эту задачу можно было бы решить, организовав LINQ-запрос через набор данных DataSet, как мы это делали в предыдущем разделе, однако мы хотим продемонстрировать и другой подход.
Вначале запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqToSqlГopoдa. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим элемент управления для отображения и редактирования табличных данных DataGridView, на этот элемент в конечном итоге будет попадать результат запроса.
Теперь создадим базу данных SQL Server. Для этого в меню Project (Проект) выберем команду Add New Item (Добавить новый элемент). В появившемся окне выберем элемент База данных, основанная на службах, а в поле Name укажем имя базы данных Города.mdf. Далее в окне мастера настройки источника данных зададим тип модели базы данных— Набор данных. Затем согласимся на сохранение строки подключения в файле конфигурации приложения. Теперь после щелчка на кнопке Готово будет создан пустой набор данных. Этот набор данных Города.mdf теперь будет виден в окне Solution Explorer (Обозреватель решений).
Чтобы заполнить этот набор данных, дважды щелкнем мышью по значку Города.mdf; таким образом, мы попадаем в окно Server Explorer/Database Explorer (Обозреватель серверов/Обозреватель баз данных). Здесь в контекстном меню узла таблицы выберем команду Добавить новую таблицу. В результате мы попадаем уже в другое окно — dbo.Table1, где зададим имена двух столбцов: Город и Население (рис. 11.14).
Рис. 11.14. Заказ полей таблицы в базе данных
При сохранении (<Ctrl>+<S>) пустой таблицы появится запрос на выбор имени для таблицы, здесь мы зададим имя Города.
Рис. 11.15. Заполнение таблицы городов в базе данных
Теперь будем заполнять сформированную таблицу. Для этого в Обозревателе серверов щелкнем правой кнопкой мыши на узле Города (имя нашей таблицы) и в появившемся контекстном меню выберем команду Показать таблицу данных Теперь в окне Города мы имеем возможность заполнять нашу таблицу (рис. 11.15).
Рис. 11.15. Заполнение таблицы городов в базе данных
На этом этапе задача создания базы данных и заполнения в ней таблицы городов выполнена. Приступаем к организации запроса к таблице городов. Как уже указывалось ранее, LINQ-запрос можно построить через набор данных DataSet, а можно LINQ-запрос организовать с помощью классов LINQ to SQL. Эти классы сопоставляются с таблицами и представлениями базы данных и называются классами сущностей DataContext. Класс сущности сопоставляется с записью, а отдельные свойства класса сущности сопоставляются с отдельными столбцами, образующими запись. Сказанное, вероятно, звучит запутанно, но практически сводится к перетаскиванию мышью созданной нами таблицы Города из окна Server Explorer/ Database Explorer (Обозреватель серверов/Обозреватель баз данных) на так называемый Object Relational Designer (реляционный конструктор объектов). В результате получим класс сущностей именно для нашей таблицы Города, наследованный от базового класса DataContext, и в тексте нашей программы уже легко сможем строить LINQ-запросы, обращаясь к объекту класса сущностей.
Чтобы получить в нашем проекте реляционный конструктор объектов, в меню Project выберем команду Add New Item (Добавить новый элемент), а в появившемся одноименном окне — шаблон (элемент) LINQ to SQL Classes. В поле Name укажем имя файла Сущности.dbml и щелкнем на кнопке Add. Внешний вид реляционного конструктора объектов можно увидеть на рис. 11.16. Теперь, как мы уже говорили, просто перетаскиваем мышью таблицу Города из окна Server Explorer/Database Explorer (Обозреватель серверов/Обозреватель баз данных) на реляционный конструктор объектов. Реляционный конструктор объектов создает классы и применяет специфические для LINQ to SQL атрибуты, чтобы иметь функциональные возможности LINQ to SQL (возможности передачи данных и редактирования, какие имеются у DataContext). А нам остается всего лишь на вкладке программного кода ввести текст, представленный на листинге 11.10.
Листинг 11.10. Организация LINQ-запроса к базе данных
// Даннoe Windows-приложение состоит из экранной формы и элемента управления BitaGridView
// В программе организован LINQ-запрос к базе данных городов с помощью базового класса сущностей DataContext.
// Для этого в данную программу добавлен (Project | Add New Item) элемент (шаблон) "Классы LINQ to SQL",
// Name=Сущности.dbml. После связывания таблицы "Города" из базы данных с базовым классом сущностей
// (путем перетаскивания мышью таблицы из окна Server Explorer/Database Explorer в окно конструктора
// Object Relational Designer) автоматически был создан класс СущностиDataContext, производный
// (наследованный) от базоваго класса DataContext. С помощью этого класса в данной программе организован
// LINQ-запрос к базе данных на получение коллекции (списка) городов, численность населения в которых
// превышает миллион жителей. Результат запроса выведен на элемент управления DataGridView.
using System;
using System. Linq;
using System.Windows.Forms ;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqToSqlГорода
{
public partial class Form1: Form
{
// С помощью объекта базового класса DataContext будем иметь доступ
// к таблице базы данных:
private СущностиDataContext БД = new СущностиDataContext();
public Form1()
{
InitializeComponent();
//В результате запроса получаем коллекцию записей из таблицы базы
// данных, удовлетворяющей условию where:
var ГородаМлн = from города in БД.Города
where Convert.ToInt32(города.Население) > 1000000
select города;
// или select new { города.Город, города.Население };
// Результат запроса выводим на элемент управления DataGridView,
// отображающий табличные данные:
dataGridView1.DataSource = ГородаМлн;
}
}
}
Фрагмент работы программы показан на рис. 11.17.
Убедиться в работоспособности программы можно, открыв реше LinqToSqlГорода.sln папки LinqToSqlГорода.
Рис. 11.17. Запрос к базе данных на города-миллионеры
Глава 12 Другие задачи, решаемые с помощью Windows Application
Пример 84. Проверка вводимых данных с помощью регулярных выражений
Данные, вводимые пользователем, должны быть проверены программой на достоверность. В этом примере мы обсудим синтаксический разбор введенной пользователем текстовой строки на соответствие ее фамилии на русском языке, а также разбор строки на соответствие ее положительному рациональному числу. Начнем с первой задачи; имеем на форме текстовое поле, метку и кнопку. В метке записано приглашение пользователю ввести фамилию на русском языке. После ввода программа должна сравнить эту строку с некоторым образцом (шаблоном, pattern) и сделать заключение, соответствует ли введенное пользователем шаблону русской фамилии.
Для решения этой задачи запустим Visual Studio 2010, выберем пункт New Project, закажем новый проект из шаблона Windows Forms Application С# и щелкнем на кнопке ОК. Затем из панели элементов управления Toolbox в форму указателем мыши перетащим текстовое поле TextBox, метку Label и командную кнопку Button. В листинге 12.1 приведен текст программы.
Листинг 12.1. Проверка вводимой фамилии с помощью регулярных выражений
// Проверка данных, вводимых пользователем, на достоверность.
// Программа осуществляет синтаксический разбор введенной пользователем
// текстовой строки на соответствие ее фамилии на русском языке
using System.Text;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace ПроверкаФамилии
{
public partial class Form1:Form
{
public Form1()
{
InitializeComponent();
Label1.Text = "Введите фамилию на русском языке:";
button1.Text = "Проверка";
}
private void button1_Click(object sender, System.EventArgs e)
{
textBox1.Text = textBox1.Text.Trim();
if (System.Text.RegularExpressions.Regex.Match(
textBox1.Text, "^[А-ИК-ЩЭ-Я][а-яА-Я]*$").Success !=true)
MessageBox.Show ("Неверный ввод фамилии", "Ошибка");
}
}
}
При обработке события "щелчок мыши на кнопке" текстовое пол textBox1.Text обрабатывается методом Trim, который удаляет все пробельные символы в начале и в конце строки. Ключевым моментом программы является проверка соответствия введенной пользователем текстовой строки и шаблона с помощью функции Regex.Match (от англ. match— соответствовать): Regex.Match(textBox1.Text, "^[А-ИК-ЩЭ-Я][а-яА-Я]*$")
Match представляет результаты из отдельного совпадения
Прежде чем решать данную задачу, давайте посмотрим отображение обсуждаемых XML-данных в табличном редакторе MS Excel (рис. 11.11).
Рис. 11.11. Отображение XML-данных в MS Excel
Как видно, в редакторе MS Excel наши XML-данные представлены весьма наглядно. И очень понятно, что мы хотим получить, а именно, все номера телефонов напротив имени "Витя".
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — Linq5. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим текстовое поле TextBoх для вывода в него найденных строк из таблицы XML. В свойствах текстового поля разрешим ввод множества строк (а не одной), для этого свойство Multiline переедем в состояние true. Затем на вкладке программного кода введем текст, представленный в листинге 11.8.
Листинг 11.8. Извлечение значения элемента из XML-данных
//Имеем XML-данные, в которых содержится таблица с именами и телефонами,
// причем имена в этой телефонной табличке повторяются. Задача состоит в том,
// чтобы в данной таблице телефонов (представленной в виде XML) найти все
// строчки с именем "Витя" с помощью LINQ-запроса
using System.Linq;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace Linq5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Text = "LINQ-запрос к XML-данным"; textBox1.Multiline = true;
// Инициализация XML-строки:
string CтрокaXML =
@"
<ТаблицаТелефонов> <Строка>
<Имена>ВитяИмена>
<Номера_телефонов>274 28 44Номера_телефонов>
Строка>
<Строка>
<Имена>АндрейИмена>
<Номера_телефонов> 8-085-45б-2378Номера_телефонов>
Строка>
<Строка>
<Имена>Карапузова ТаняИмена>
<Номера_телефонов>4 45-56-47Номера_телефонов>
<Строка>
<Имена>ВитяИмена>
<Номера_телефонов>099 72 161 52Номера_телефонов>
Строка>
<Строка>
<Имена>НикипеловИмена>
<Номера_телефонов>2 3 6-77-7 6Номера_телефонов>
Строка>
<Строка>
<Имена>ЗиборовИмена>
<Номера_телефонов>254 67 97Номера_телефонов>
Строка>
ТаблицаТелефонов>";
var КорневойЭлемент = System.Xml.Linq.XElement.Parse(CтрoкaXML);
// Запись строки, содержащей XML, в, файл:
// System.IO.File.WriteAllText("ТаблицаТелефонов.xml", CтрокaXML);
// var КорневойЭлемент = System.Xml.Linq.
// XElement.Load("ТаблицаТелефонов.xml");
var Записи = from x in КорневойЭлемент.Elements("Строка")
where (string)x.Element("Именa") == "Витя"
select x.Element ("Номера_телефонов") .Value;
textBox1.Text = textBox1.Text + @"Строки, содержащие имя ""Витя"":" + "\r\n";
// Вывод коллекции записей в текстовое поле textBox1:
foreach (var х in Записи)
textBox1.Text = textBox1.Text + x + "\r\n";
// Таких записей в этой коллекции - ровно одна
}
}
}
Как видно, в начале программы мы инициализируем (т.е. присваиваем начальные значения) XML-строку. Далее извлекаем корневой элемент из XML-документа, oн, по сути, отличается от XML-документа отсутствием XML-объявления (в этом можно убедиться в отладчике программы). В комментарии указано, как можно получить корневой элемент в том случае, если он представлен в виде XML-файла во внешней памяти. Затем организуем типовой, стандартный LINQ-запрос. Результат запроса попадает в коллекцию записей, которую выводим в текстовое поле, используя оператор цикла foreach. Фрагмент работы программы показан на рис. 11.12.
Убедиться в работоспособности программы можно, открыв решение Linq5.sln из папки Linq5.
Рис. 11.12. LINQ-запрос к XML-документу
Пример 82. LINQ-запрос к набору данных DataSet
Весьма полезной оказывается организация LINQ-запросов к наборам данных DataSet, используемым, к примеру, при работе с базами данных. Объект класса DataSet представляет расположенный в памяти кэш (cache) данных (кэш — это промежуточная память с быстрым доступом, содержащая информацию, которая может быть запрошена с наибольшей вероятностью). Реляционные базы данных работают чаще всего с совокупностью таблиц. Каждая из этих таблиц задается как объект класса DataTable, один такой объект представляет ровно одну таблицу данных. Набор данных DataSet содержит в себе несколько объектов (таблиц) DataTable. Запросы LINQ к таблицам данных, кэшированным в объекте
DataSet, упрощают и ускоряют процесс отбора.
Данная задача состоит в том, чтобы создать программу, которая обеспечивает ввод простейшей таблицы, содержащей два поля — название города и численное его населения. Программа способна фильтровать данные в таблице; будем производить отбор городов, численность населения которых превышает миллион жителей.
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqГopoдa. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим элемент управления для отображения и редактирования табличных данных DataGridView, две командные кнопки Button и текстовое поле TextBox. Одна кнопка предназначена для команды сохранения данных, другая — для поиска данных в таблице, а текстовое поле — для вывода в него найденных строк из таблицы. В свойствах текстового поля разрешим ввод множества строк, для этого свойство Multiline переведем в состояние truе. Затем на вкладке программного кода введем текст, представленный в листинге 11.9. I
Листинг 11.9. Извлечение полей из набора данных DataSet
//В данной программе экранная форма содержит элемент управления
// для отображения и редактирования табличных данных DataGridView,
// две командные кнопки и текстовое поле. При старте программы,
// если есть соответствующий файл XML, программа отображает
//в DataGridView таблицу городов - название города и численность населения.
// При щелчке на кнопке "Сохранить" все изменения в таблице записываются
// в XML-файл. При щелчке на второй кнопке "Найти" выполняется LINQ-запрос
// к набору данных DataSet на поиск городов-миллионеров в искомой таблице.
//Pезультат запроса выводится в текстовое поле.
using System;
using System.Data;
usingSystem.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace _LinqГopoдa
{
public partial class Form1 : Form
{
DataTable Таблица = new DataTabie(); // Создание объекта "таблица данных"
DataSet НаборДанных = new DataSetО; // Создание объекта "набор данных"
public Form1()
{
InitializeComponent();
base.Text = "LINQ-запрос к набору данных DataSet";
button1.Text = "Сохранить"; button2.Text = "Найти";
textBox1.Multiline = true;
if (System.IO.File.Exists("Города.xml") == false)
{ // Если XML-файла НЕТ:
// заполнение "шапки" таблицы
Таблица.Columns . Add ("Город") ; Таблица. Columns . Add ("Население");
// Добавить объект Таблица в DataSet:
НаборДанных.Таbles.Add(Таблица);
dataGridView1.DataSource = Таблица;
}
else // Если XML-файл ЕСТЬ:
{
НаборДанных. ReadXml (" Города. xml");
// Содержимое DataSet в виде строки XML для отладки:
// string CтрокaXML = НаборДанных.GetXml();
Таблица = НаборДанных.Tables["Города"];
dataGridView1.DataMember = "Города";
dataGridView1.DataSource = НаборДанных;
}
}
private void button1_Click(object sender, EventArgs e)
{ // Щелчок мышью на кнопке "Сохранить" - сохранить файл Города.xml:
Таблица.TableName = "Города";
НаборДанных.WriteXml("Города.xml");
}
private void button2_Click(object sender, EventArgs e)
{ // Щелчок мышью на кнопке "Поиск" - запрос городов-миллионеров:
textBoxl.Clear(); // - очистка текстового поля
var ГородаМлн = from Город in Таблица.AsEnumerable()
where Convert.ToInt32(Город.
Field
select new
{
A = Город.Field
В = Город.Field
};
textBox1. Text = textBox1. Text + "Города-миллионеры: \r\n";
// Вывод результата запроса в текстовое поле textBox1:
foreach (var Город in ГородаМлн) textBox1.Text = textBox1.Text +
Город.A + " - " + Город.В + "\r\n";
}
}
}
В начале программы создаем объекты классов DataSet и DataTable так, чтобы они были видимыми из всех процедур класса Form1. Далее сразу после инициализации компонентов экранной формы (т. е. после выполнения процедуры InitializeComponent) проверяем, существует ли файл Города.хml, куда мы записываем искомую таблицу. Если файл не существует, т. е. пользователь первый раз запустил нашу программу, то мы создаем таблицу, состоящую из двух полей (колонок): "Город" и "Население", добавляем (Add) эту таблицу в набор данных , а также указываем таблицу в качестве источника данных (DataSource) для сеянных dataGridView1. Если же файл Города.xml уже создан, то мы читаем егo в набор данных DataSet и из него заполняем таблицу данных, а также этот набор данных указываем в качестве источника для сетки данных.
При обработке события "щелчок мышью на кнопке" Запись программируем сохранение редактируемой таблицы в файле Города.хml. В процедуре обработки события "щелчок на кнопке" Найти организуем LINQ-запрос к заполненной пользователем таблице DataTable, являющейся представителем DataSet. Условием запроса является отбор таких полей таблицы, где население превышает миллион жителей. Заметим, что если не задавать условие where, то в результате запроса получим все содержимое источника данных, т. е. все строки таблицы городов. Результат запроса выводим в текстовое поле, используя цикл foreach.
Фрагмент работы программы показан на рис. 11.13.
Убедиться в работоспособности программы можно, открыв решение LinqГopoдa.sln из папки LinqГopoдa.
Рис. 11.13. LINQ-запрос к набору данных
Пример 83. Доступ к базе данных с помощью LINQ to SQL
В данном примере вначале создадим базу данных городов, содержащую два поля: название города и численность его населения. Затем организуем доступ к этой базе данных с помощью LINQ to SQL и создадим запрос на извлечение коллекции городов, численность населения в которых превышает миллион жителей. Эту задачу можно было бы решить, организовав LINQ-запрос через набор данных DataSet, как мы это делали в предыдущем разделе, однако мы хотим продемонстрировать и другой подход.
Вначале запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqToSqlГopoдa. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим элемент управления для отображения и редактирования табличных данных DataGridView, на этот элемент в конечном итоге будет попадать результат запроса.
Теперь создадим базу данных SQL Server. Для этого в меню Project (Проект) выберем команду Add New Item (Добавить новый элемент). В появившемся окне выберем элемент База данных, основанная на службах, а в поле Name укажем имя базы данных Города.mdf. Далее в окне мастера настройки источника данных зададим тип модели базы данных— Набор данных. Затем согласимся на сохранение строки подключения в файле конфигурации приложения. Теперь после щелчка на кнопке Готово будет создан пустой набор данных. Этот набор данных Города.mdf теперь будет виден в окне Solution Explorer (Обозреватель решений).
Чтобы заполнить этот набор данных, дважды щелкнем мышью по значку Города.mdf; таким образом, мы попадаем в окно Server Explorer/Database Explorer (Обозреватель серверов/Обозреватель баз данных). Здесь в контекстном меню узла таблицы выберем команду Добавить новую таблицу. В результате мы попадаем уже в другое окно — dbo.Table1, где зададим имена двух столбцов: Город и Население (рис. 11.14).
Рис. 11.14. Заказ полей таблицы в базе данных
При сохранении (<Ctrl>+<S>) пустой таблицы появится запрос на выбор имени для таблицы, здесь мы зададим имя Города.
Рис. 11.15. Заполнение таблицы городов в базе данных
Теперь будем заполнять сформированную таблицу. Для этого в Обозревателе серверов щелкнем правой кнопкой мыши на узле Города (имя нашей таблицы) и в появившемся контекстном меню выберем команду Показать таблицу данных Теперь в окне Города мы имеем возможность заполнять нашу таблицу (рис. 11.15).
Рис. 11.15. Заполнение таблицы городов в базе данных
На этом этапе задача создания базы данных и заполнения в ней таблицы городов выполнена. Приступаем к организации запроса к таблице городов. Как уже указывалось ранее, LINQ-запрос можно построить через набор данных DataSet, а можно LINQ-запрос организовать с помощью классов LINQ to SQL. Эти классы сопоставляются с таблицами и представлениями базы данных и называются классами сущностей DataContext. Класс сущности сопоставляется с записью, а отдельные свойства класса сущности сопоставляются с отдельными столбцами, образующими запись. Сказанное, вероятно, звучит запутанно, но практически сводится к перетаскиванию мышью созданной нами таблицы Города из окна Server Explorer/ Database Explorer (Обозреватель серверов/Обозреватель баз данных) на так называемый Object Relational Designer (реляционный конструктор объектов). В результате получим класс сущностей именно для нашей таблицы Города, наследованный от базового класса DataContext, и в тексте нашей программы уже легко сможем строить LINQ-запросы, обращаясь к объекту класса сущностей.
Чтобы получить в нашем проекте реляционный конструктор объектов, в меню Project выберем команду Add New Item (Добавить новый элемент), а в появившемся одноименном окне — шаблон (элемент) LINQ to SQL Classes. В поле Name укажем имя файла Сущности.dbml и щелкнем на кнопке Add. Внешний вид реляционного конструктора объектов можно увидеть на рис. 11.16. Теперь, как мы уже говорили, просто перетаскиваем мышью таблицу Города из окна Server Explorer/Database Explorer (Обозреватель серверов/Обозреватель баз данных) на реляционный конструктор объектов. Реляционный конструктор объектов создает классы и применяет специфические для LINQ to SQL атрибуты, чтобы иметь функциональные возможности LINQ to SQL (возможности передачи данных и редактирования, какие имеются у DataContext). А нам остается всего лишь на вкладке программного кода ввести текст, представленный на листинге 11.10.
Листинг 11.10. Организация LINQ-запроса к базе данных
// Даннoe Windows-приложение состоит из экранной формы и элемента управления BitaGridView
// В программе организован LINQ-запрос к базе данных городов с помощью базового класса сущностей DataContext.
// Для этого в данную программу добавлен (Project | Add New Item) элемент (шаблон) "Классы LINQ to SQL",
// Name=Сущности.dbml. После связывания таблицы "Города" из базы данных с базовым классом сущностей
// (путем перетаскивания мышью таблицы из окна Server Explorer/Database Explorer в окно конструктора
// Object Relational Designer) автоматически был создан класс СущностиDataContext, производный
// (наследованный) от базоваго класса DataContext. С помощью этого класса в данной программе организован
// LINQ-запрос к базе данных на получение коллекции (списка) городов, численность населения в которых
// превышает миллион жителей. Результат запроса выведен на элемент управления DataGridView.
using System;
using System. Linq;
using System.Windows.Forms ;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqToSqlГорода
{
public partial class Form1: Form
{
// С помощью объекта базового класса DataContext будем иметь доступ
// к таблице базы данных:
private СущностиDataContext БД = new СущностиDataContext();
public Form1()
{
InitializeComponent();
//В результате запроса получаем коллекцию записей из таблицы базы
// данных, удовлетворяющей условию where:
var ГородаМлн = from города in БД.Города
where Convert.ToInt32(города.Население) > 1000000
select города;
// или select new { города.Город, города.Население };
// Результат запроса выводим на элемент управления DataGridView,
// отображающий табличные данные:
dataGridView1.DataSource = ГородаМлн;
}
}
}
Фрагмент работы программы показан на рис. 11.17.
Убедиться в работоспособности программы можно, открыв реше LinqToSqlГорода.sln папки LinqToSqlГорода.
Рис. 11.17. Запрос к базе данных на города-миллионеры
Глава 12 Другие задачи, решаемые с помощью Windows Application
Пример 84. Проверка вводимых данных с помощью регулярных выражений
Данные, вводимые пользователем, должны быть проверены программой на достоверность. В этом примере мы обсудим синтаксический разбор введенной пользователем текстовой строки на соответствие ее фамилии на русском языке, а также разбор строки на соответствие ее положительному рациональному числу. Начнем с первой задачи; имеем на форме текстовое поле, метку и кнопку. В метке записано приглашение пользователю ввести фамилию на русском языке. После ввода программа должна сравнить эту строку с некоторым образцом (шаблоном, pattern) и сделать заключение, соответствует ли введенное пользователем шаблону русской фамилии.
Для решения этой задачи запустим Visual Studio 2010, выберем пункт New Project, закажем новый проект из шаблона Windows Forms Application С# и щелкнем на кнопке ОК. Затем из панели элементов управления Toolbox в форму указателем мыши перетащим текстовое поле TextBox, метку Label и командную кнопку Button. В листинге 12.1 приведен текст программы.
Листинг 12.1. Проверка вводимой фамилии с помощью регулярных выражений
// Проверка данных, вводимых пользователем, на достоверность.
// Программа осуществляет синтаксический разбор введенной пользователем
// текстовой строки на соответствие ее фамилии на русском языке
using System.Text;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace ПроверкаФамилии
{
public partial class Form1:Form
{
public Form1()
{
InitializeComponent();
Label1.Text = "Введите фамилию на русском языке:";
button1.Text = "Проверка";
}
private void button1_Click(object sender, System.EventArgs e)
{
textBox1.Text = textBox1.Text.Trim();
if (System.Text.RegularExpressions.Regex.Match(
textBox1.Text, "^[А-ИК-ЩЭ-Я][а-яА-Я]*$").Success !=true)
MessageBox.Show ("Неверный ввод фамилии", "Ошибка");
}
}
}
При обработке события "щелчок мыши на кнопке" текстовое пол textBox1.Text обрабатывается методом Trim, который удаляет все пробельные символы в начале и в конце строки. Ключевым моментом программы является проверка соответствия введенной пользователем текстовой строки и шаблона с помощью функции Regex.Match (от англ. match— соответствовать): Regex.Match(textBox1.Text, "^[А-ИК-ЩЭ-Я][а-яА-Я]*$")
Match представляет результаты из отдельного совпадения