Украина, Киев |
Объект 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).