Опубликован: 05.08.2007 | Уровень: специалист | Доступ: платный
Лекция 9:

Объект DataView. Вывод связанных таблиц

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >

Свойство 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):

 Определение первичного ключа в редакторе Tables Collection Editor

Рис. 9.15. Определение первичного ключа в редакторе Tables Collection Editor

После определения первичного ключа объекта DataTable для свойства AllowDBNull (разрешение значений null) объектов DataColumn, формирующих ключ, будет установлено значение false.

В проектах, содержащих большое количество связанных таблиц, следует всегда определять свойство PrimaryKey. Это должно стать таким же правилом, как и задание первичного ключа при проектировании самой базы данных.

Поиск данных

Технология ADO .NET предоставляет значительные возможности для поиска данных - такие объекты, как DataSet, DataTable, содержат специализированные методы для быстрого решения этой задачи. Между тем свойство RowFilter объекта DataView может применяться для создания простого и эффективного поиска. Запускаем Visual Studio .NET и создаем новый проект. В окне New Project выбираем тип Windows Control Library, называем его "FindControl" (рис. 9.16):

 Выбор шаблона Windows Control Library

Рис. 9.16. Выбор шаблона Windows Control Library

Появляется форма пользовательского (композитного) элемента управления. Устанавливаем следующие свойства:

UserControl1, свойство Значение
Name FindCheckBox
Size 230; 70

В окне 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
label1, свойство Значение
Name lblColumnName
Location 40; 8
Text ColumnName

Переходим к коду. В конструкторе формы отключаем доступность текстового поля и привязываем обработчик события 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, В).

 Добавление композитного элемента. А - окно "Customize Toolbox", Б - Выбор сборки FindControl.dll, В - добавленная сборка на вкладке ".NET Framework Components"

увеличить изображение
Рис. 9.17. Добавление композитного элемента. А - окно "Customize Toolbox", Б - Выбор сборки FindControl.dll, В - добавленная сборка на вкладке ".NET Framework Components"

Нажимаем кнопку "OK" и перетаскиваем на панель формы из окна Toolbox четыре копии элемента FindCheckBox. Добавляем также кнопку поиска (рис. 9.18). Устанавливаем следующие свойства элементов:

findCheckBox1, свойство Значение
ColumnName CustomerID
Name fcbCustomerID
findCheckBox2, свойство Значение
ColumnName CompanyName
Name fcbCompanyName
findCheckBox3, свойство Значение
ColumnName ContactName
Name FcbContactName
findCheckBox4, свойство Значение
ColumnName Phone
Name fcbPhone
button1, свойство Значение
Name btnSearch
Text Поиск
 Расположение элементов на форме. Окно Properties композитного элемента

увеличить изображение
Рис. 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, Б).

 Готовое приложение "FindCustomers". А - Запрос с оператором "ИЛИ" возвращает две записи, содержащие в разных полях введенное значение. Б - Запрос с оператором "И" не возвращает ничего, поскольку в таблице нет ни одной записи, содержащей оба значения

увеличить изображение
Рис. 9.19. Готовое приложение "FindCustomers". А - Запрос с оператором "ИЛИ" возвращает две записи, содержащие в разных полях введенное значение. Б - Запрос с оператором "И" не возвращает ничего, поскольку в таблице нет ни одной записи, содержащей оба значения

В программном обеспечении к курсу вы найдете приложения FindControl и FindCustomers (Code\Glava4\ FindControl и FindCustomers).

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >
Александра Тимофеева
Александра Тимофеева
Украина, Киев
Bakke Aleksander
Bakke Aleksander
Россия, Mуниципальный округ N 4