Объект DataView. Вывод связанных таблиц
Свойство PrimaryKey
Мы научились конструировать структуру таблицы в объекте DataSet, а также определять отношения между таблицами. Во всех случаях для выделения первичного ключа в таблице использовалось свойство Unique. Например, в самом последнем примере - проекте Programm2DataGrid2Table - первичный ключ "Код туриста" определялся так:
...
DataColumn dcTouristID = new DataColumn("Код туриста", typeof(int));
dcTouristID.Unique = true;
...
DataColumn dcInfoTouristsID = new DataColumn("Код туриста", typeof(int));
dcInfoTouristsID.Unique = true;
...Для вывода таблиц идентификации записей этого определения вполне хватало. Однако свойство Unique всего лишь указывает на уникальность заданного поля, т.е. на отсутствие повторяющихся записей. В самом деле, в таблице может быть несколько полей, которые должны быть уникальными и одно из них (или их комбинация) будут образовывать первичный ключ. Для указания именно первичного ключа используется свойство PrimaryKey объекта DataTable:
DataTable dtTourists = new DataTable("Туристы");
DataColumn dcTouristID = new DataColumn("Код туриста", typeof(int));
dtTourists.PrimaryKey = new DataColumn [] {dtTourists.Columns["Код туриста"]};В сокращенной записи определение будет такое:
dtTourists.Columns.Add("Код туриста", typeof(int));
dtTourists.PrimaryKey = new DataColumn [] {dtTourists.Columns["Код туриста"]};Можно применять комбинацию полей для задания первичного ключа:
DataTable dtTourists = new DataTable("Туристы");
DataColumn dcTouristID =
new DataColumn("Код туриста", typeof(int));
DataColumn dcLastName =
new DataColumn("Фамилия",typeof(string));
dtTourists.PrimaryKey =
new DataColumn [] {dtTourists.Columns["Код туриста"],
dtTourists.Columns["Фамилия"]};Здесь первичным ключом будут значения поля "Код туриста" в сочетании со значением поля "Фамилия".
При конструировании объекта DataTable в редакторе Tables Collection Editor после создания объектов Columns в свойстве PrimaryKey можно выделять одно или несколько полей - они отмечаются числами и становятся первичным ключом (рис. 9.15):
После определения первичного ключа объекта DataTable для свойства AllowDBNull (разрешение значений null) объектов DataColumn, формирующих ключ, будет установлено значение false.
В проектах, содержащих большое количество связанных таблиц, следует всегда определять свойство PrimaryKey. Это должно стать таким же правилом, как и задание первичного ключа при проектировании самой базы данных.
Поиск данных
Технология ADO .NET предоставляет значительные возможности для поиска данных - такие объекты, как DataSet, DataTable, содержат специализированные методы для быстрого решения этой задачи. Между тем свойство RowFilter объекта DataView может применяться для создания простого и эффективного поиска. Запускаем Visual Studio .NET и создаем новый проект. В окне New Project выбираем тип Windows Control Library, называем его "FindControl" (рис. 9.16):
Появляется форма пользовательского (композитного) элемента управления. Устанавливаем следующие свойства:
В окне Solution Explorer изменяем название "UserControl1.cs" на "FindCheckBox.cs". Перетаскиваем на форму из окна Toolbox текстовое поле, надпись и элемент CheckBox. Настраиваем их свойства:
| CheckBox1, свойство | Значение |
|---|---|
| Name | chbForSearching |
| Location | 8; 32 |
| Text | |
| textBox1, свойство | Значение |
| Name | txtColumnValue |
| Location | 32; 32 |
| Size | 184; 20 |
| Text |
Переходим к коду. В конструкторе формы отключаем доступность текстового поля и привязываем обработчик события CheckedChanged для элемента CheckBox:
public FindCheckBox()
{
InitializeComponent();
txtColumnValue.Enabled = false;
chbForSearching.CheckedChanged +=
new EventHandler(chbForSearching_CheckedChanged);
}В классе формы создаем обработчик события CheckedChanged для CheckBox и определяем действия для значений текстового поля, надписи и элемента CheckBox:
private void chbForSearching_CheckedChanged(object sender, EventArgs e)
{
txtColumnValue.Enabled = chbForSearching.Checked;
}
[Category("Appearance"),
Description("Название поля, по которому будет осуществляться поиск")]
public string ColumnName
{
get {return lblColumnName.Text;}
set {lblColumnName.Text = value;}
}
[Category("Appearance"), Description("Ключевое слово для поиска")]
public string ColumnValue
{
get {return txtColumnValue.Text;}
set {txtColumnValue.Text = value;}
}
[Category("Appearance"), Description("Включение поиска по заданному полю")]
public bool SearchEnabled
{
get {return chbForSearching.Checked;}
set {chbForSearching.Checked = value;}
}Свойства ColumnName, ColumnValue и SearchEnabled будут свойствами композитного элемента управления, которые будут отображаться в его окне Properties. В квадратных скобках указан атрибут для помещения свойства в заданную группу и описание, выводимое на информационную панель. Компилируем приложение (Ctrl+Shift+B) и закрываем его. Создаем новое Windows-приложение, называем его "FindCustomers". Перетаскиваем на форму следующие элементы управления: Panel (свойству Dock устанавливаем значение Left ), Splitter и DataGrid (свойству Dock устанавливаем значение Fill ). В окне Toolbox щелкаем правой кнопкой мыши на вкладке Windows Forms и в появившемся контекстном меню выбираем пункт "Add \ Remove Items_". В появившемся окне Customize Toolbox на вкладке .NET Framework Components нажимаем кнопку "Browse" (рис. 9.17, А) и переходим в директор ию, где расположена сборка композитного элемента FindControl (у меня это D:\Uchebnik\Code\Glava4\FindControl\bin\Debug, сборка FindControl.dll) (рис. 9.17, Б). После выбора сборки она появляется в окне Customize Toolbox (рис. 9.17, В).
увеличить изображение
Рис. 9.17. Добавление композитного элемента. А - окно "Customize Toolbox", Б - Выбор сборки FindControl.dll, В - добавленная сборка на вкладке ".NET Framework Components"
Нажимаем кнопку "OK" и перетаскиваем на панель формы из окна Toolbox четыре копии элемента FindCheckBox. Добавляем также кнопку поиска (рис. 9.18). Устанавливаем следующие свойства элементов:
увеличить изображение
Рис. 9.18. Расположение элементов на форме. Окно Properties композитного элемента
Обратите внимание (рис. 9.18), что в окне Properties, при групповом расположении, свойство ColumnName находится в группе Appearance. На информационную панель выводится описание этого свойства на русском языке. Именно эти параметры мы и указывали при создании композитного элемента.
Для того чтобы упростить код, создадим подключение к базе данных при помощи визуальных средств студии. В окне Toolbox переходим на вкладку Data, перетаскиваем на форму SqlDataAdapter и настраиваем извлечение таблицы Customers базы данных NorthwindCS. Выделяем затем sqlDataAdapter1 на панели компонент, в окне Properties переходим по ссылке "Generate DataSet". Вводим имя "dsCustomers". В конструкторе формы добавляем код для заполнения элемента DataGrid данными при загрузке:
public Form1()
{
InitializeComponent();
sqlDataAdapter1.Fill(dsCustomers1);
dataGrid1.DataSource = dsCustomers1.Tables["Customers"].DefaultView;
}В классе формы создаем метод FindCustomers, в котором будет осуществляться обработка1Дополнительные сведения о классе ArrayList см. в конце лекции.:
private void FindCustomers()
{
//Создаем экземпляр filteringFields класса ArrayList
ArrayList filteringFields = new ArrayList();
//Если элемент fcbCustomerID доступен для поиска
if (fcbCustomerID.SearchEnabled)
//Добавляем в массив filteringFields значение текстового поля ColumnValue
filteringFields.Add("CustomerID LIKE \'" +
fcbCustomerID.ColumnValue + "%\'");
if (fcbCompanyName.SearchEnabled)
filteringFields.Add("CompanyName LIKE \'" +
fcbCompanyName.ColumnValue + "%\'");
if (fcbContactName.SearchEnabled)
filteringFields.Add("ContactName LIKE \'" +
fcbContactName.ColumnValue + "%\'");
if (fcbPhone.SearchEnabled)
filteringFields.Add("Phone LIKE \'" +
fcbPhone.ColumnValue + "%\'");
string filter = "";
//Комбинируем введенные в текстовые поля значения.
//Для объединения используем логический оператор "ИЛИ"
if (filteringFields.Count == 1)
filter = filteringFields[0].ToString();
else if (filteringFields.Count > 1)
{
for(int i = 0; i < filteringFields.Count - 1; i++)
filter += filteringFields[i].ToString() + " OR ";
//Для объединения полей в запросе используем логический оператор "И"
//for(int i = 0; i < filteringFields.Count - 1; i++)
//filter += filteringFields[i].ToString() + " AND ";
filter += filteringFields[filteringFields.Count - 1].ToString();
}
//Создаем экземпляр dvSearch класса DataView
DataView dvSearch = new DataView(dsCustomers1.Customers);
//Передаем свойству RowFilter объекта DataView скомбинированное значение filter
dvSearch.RowFilter = filter;
dataGrid1.DataSource = dvSearch;
}Добавляем обработчик кнопки "Поиск":
private void btnSearch_Click(object sender, System.EventArgs e)
{
try
{
FindCustomers();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}Запускаем приложение. При определении логического оператора "ИЛИ" в методе FindCustomers поисковый запрос выводит записи, содержащие хотя бы одно значение из введенных полей (рис. 9.19, А), при определении оператора "И" - запись, содержащую все эти значения (рис. 9.19, Б).
увеличить изображение
Рис. 9.19. Готовое приложение "FindCustomers". А - Запрос с оператором "ИЛИ" возвращает две записи, содержащие в разных полях введенное значение. Б - Запрос с оператором "И" не возвращает ничего, поскольку в таблице нет ни одной записи, содержащей оба значения
В программном обеспечении к курсу вы найдете приложения FindControl и FindCustomers (Code\Glava4\ FindControl и FindCustomers).




