Навигацията "главен/подчинен" (master-details) отразява взаимоотношения от тип едно към много (например един регион има много области). В ADO.NET DataSet обектите поддържат релации от тип "главен/подчинен". За целта се използват DataRelation обектите в DataSet.
В Windows Forms се поддържа навигация "главен/подчинен". За да илюстрираме работата с нея, нека разгледаме един пример: Имаме DataSet, съдържащ две таблици – едната съдържа имена на държави, а другата – имена на градове. Те са свързани помежду си така, че на всяка държава от първата таблица съответстват определени градове от втората таблица:
Тогава можем да използваме две DataGrid контроли – първата, визуализираща държавите, а втората, визуализираща градовете, съответстващи на текущо избраната държава от първата контрола. За целта контролите се свързват с един и същ DataSet. На главната контрола се задава за източник на данни главната таблица. На подчинената контрола се задава за източник на данни релацията на таблицата:
// Bind the master grid to the master table
DataGridCountries.DataSource = datasetCountriesAndTowns;
DataGridCountries.DataMember = "Countries";
// Bind the detail grid to the relationship
DataGridTowns.DataSource = datasetCountriesAndTowns;
DataGridTowns.DataMember = "Countries.CountriesTowns";
| Master-Details навигация – пример
Настоящият пример илюстрира възможностите за реализация на Master-Details навигация, базирана на DataSet компонентата от ADO.NET и сложното свързване на списъчни контроли в Windows Forms. В примера ще използваме базата данни Northwind – една от стандартните демонстрационни бази в MS SQL Server.
Ще създадем приложение, което има в главната си форма две контроли – ListBox, който показва региони (от таблицата Region от базата данни), и DataGrid, който показва областите за всеки регион (от таблицата Territories от базата данни).
Ето и стъпките за изграждане на нашето приложение:
-
Стартираме VS.NET и създаваме нов Windows Forms проект.
-
Задаваме на главната форма име MainForm и заглавие "Master-Detail Demo". Променяме и името на файла от Form1.cs на MainForm.cs.
-
В прозореца Server Explorer от VS.NET намираме демонстрационната база данни Northwind на MS SQL Server. Щракваме върху таблицата Region и след това, натискайки клавиш Ctrl, щракваме върху таблицата Territories. След като сме маркирали едновременно и двете таблици, ги извличаме върху формата. Ако прозорецът Server Explorer не е отворен, можем да го отворим, като изберем View | Server Explorer.
-
Windows Forms редакторът автоматично създава за нас един SqlConnection и два SqlDataAdapter компонента. Променяме техните имена съответно на sqlConneciton, sqlDataAdapterRegion и sqlDataAdapterTerritories:
-
От менюто Data избираме Generate Dataset… В появилия се прозорец указваме, че искаме да създадем нов DataSet и задаваме за име DataSetNorthwind. Поставяме отметки и пред двете таблици и натискаме бутона [OK], за да създадем новия DataSet. Променяме името на появилия се в редактора DataSet на dataSetNorthwind.
-
Щракваме с десния бутон върху dataSetNorthwind в редактора и от появилото се контекстно меню избираме View Schema… Отваря се файлът DataSetNorthwind.xsd - виждаме XSD схемата на DataSet-a, генериран на базата на таблиците Region и Territories.
-
От Toolbox извличаме един Relation обект и го пускаме върху таблицата Territories. В появилия се прозорец се уверяваме, че за Parent element e избрана таблицата Region, а за Child element - таблицата Territories, и натискаме бутона OK. Така дефинирахме релация тип Master-Details между таблиците Region и Territories.
-
Добавяме във формата един ListBox с име ListBoxRegions. На свойството DataSource задаваме стойност dataSetNorthwind, а на свойствата DisplayMember и ValueMember – съответно стойности Region.RegionDescription и Region.RegionID.
-
Добавяме във формата един DataGrid с име DataGridTerritories. Задаваме на свойствата DataSource и DataMember съответно стойности dataSetNorthwind и Region.RegionTerritories.
-
Дефинираме стил с име dataGridTableStyleTerritories за таблицата Territories. В колекцията му GridColumnStyles добавяме стилове за полетата TerritoryID и TerritoryDescription, като указваме, че тези колони трябва да са със заглавия - съответно код и област.
-
Добавяме код, който при зареждане на формата (при събитие Load) зарежда DataSet обекта от базата данни чрез DataAdapter компонентите за двете таблици (Region и Territories):
private void MainForm_Load(object sender, System.EventArgs e)
{
sqlDataAdapterRegion.Fill(dataSetNorthwind);
sqlDataAdapterTerritories.Fill(dataSetNorthwind);
}
| -
Приложението е готово и можем да го стартираме и тестваме:
Проблеми при Master-Details навигацията
Показаният начин за реализация на master-details навигация е лесен за използване, но има един сериозен проблем: винаги зарежда в паметта всички записи от двете таблици. Ако таблиците са обемни, този подход ще работи много бавно или въобще няма да работи. Причината е, че зареждането на голям обем записи (да кажем няколко хиляди) в DataSet изисква много памет и става бавно.
Ако данните са много, можем да подходим по следния начин: Зареждаме всички данни от главната (master) таблица и ги визуализираме с DataGrid или ListBox. След това прихващаме събитието "смяна на текущия ред" и при неговото настъпване зареждаме в подчинената (details) таблица детайлните записи за избрания запис от главната таблица. Зареждането може да се извърши с параметрична SQL заявка, изпълнена през SqlDataReader или SqlDataAdapter.
Релации "много към много"
DataSet и DataGrid не поддържат релации тип "много към много". Такъв тип релации могат да бъдат сведени до Master-Details чрез добавяне на изглед в базата данни. Нека примерно имаме база данни, съдържаща таблици Courses и Students и таблица StudentsCourses, осъществяваща връзка между тях.
За да сведем тази релация към Master-Details, можем да създадем изглед в базата данни:
CREATE VIEW View_StudentsCourses AS
SELECT StudentId, StudentName, CourseId, CourseName
FROM Students, Courses, StudentsCourses
WHERE Students.StudentsId = StudentsCourses.StudentId
AND Courses.CourseId = StudentsCourses.CourseId
|
След като сме създали изгледа, можем да сведем релацията до релация Master-Details между таблицата Courses и новосъздадения изглед:
Аналогично на предходния пример можем да работим с таблиците, които са вече във взаимоотношение "главен/подчинен":
Сподели с приятели: |