Zugriffe auf Datenbanken wie SQL-Server oder andere, sollten in jeder Anwendung aufs Nötigste beschränkt werden. Um ein paar Daten
zum Beispiel auf eine WebForm zu bringen 3, 4 mal die Datenbank zu konsultieren, bis man alle Daten zusammen hat, ist ineffizient und bedeutet
Perfomance-Verlust.
Bei der Anzeige hierarchisch strukturierter Daten wird dieser mehrfache Zugriff jedoch oft in Kauf genommen, um die einzelnen Ebenen getrennt
voneinander verarbeiten zu können. In Zeiten von LINQ ist dies eigentlich unnötig, da man hier Daten auch gruppieren kann. Jedoch gibt es auch
Alternativen, wenn zum Beispiel der Web-Provider das .NET-Framework 3.5 noch nicht unterstützt oder man die Einarbeitungszeit in LINQ scheut.
Auch können LINQ-Statements mit 5 oder 6 Ebenen extrem unübersichtlich werden und somit die Wartbarkeit des Codes verschlechtern.
Die Beispieldaten
Sagen wir mal, es sollen Budgetdaten auf einer WebForm ausgegeben werden und das ensprechende SQL-Statement ermittelt über Joins bereits alle
dafür notwendigen Daten aus den beteiligten Tabellen der Datenbank. Die flache Tabelle, ausgegeben in einem Datagrid, könnte somit wie folgt
aussehen:
Die einzelnen Employees sollen aber nun mit Ihrem Budgetwert, gruppiert nach dem Monat, ausgegeben werden. Ungefähr so:

Um die Daten in einer solchen Form auszugeben, kann man nun geschachtelte Repeater verwenden, d.h. das ItemTemplate des ersten
Repeaters enthält die Ausgabe des Monatsnamens und einen weiteren Repeater zur Ausgabe der Felder Employee und Budget.
Bevor man damit jedoch loslegen kann, müssen die Daten erst in eine Hierarchie gebracht werden, deren Ebenen man an die Repeater binden kann.
Hierzu kann man, wie oben erwähnt, entweder LINQ verwenden oder die recht simple Klasse HierarchyList und ihre Unterklassen.
Die Hierarchie-Klassen
Basistechnik der Klasse HierarchyList ist eine generische Liste, die Elemente des Typs
HierarchyItem aufnimmt. Jeder Eintrag enthält eine Liste des Typs HierarchyField und ein weiteres Objekt namens
SubItems, welches wiederum vom Typ HierarchyList ist. Mit diesem einfachen Konstrukt lassen sich Daten unendlich schachteln.
Die obigen Beispieldaten aus einer DataTable in eine Instanz der Klasse HierarchyList zu füllen ist denkbar einfach:
'Hierarchieliste initialisieren
Dim h As New HierarchyList
For Each dr As DataRow In ds.Tables(0).Rows
'1. Ebene ablegen
Dim h1 As HierarchyItem = h.AddItem(dr.Item("Month")) 'Schlüssel
h1.AddField("L1_Month", dr.Item("Month")) 'Feld
'2. Ebene ablegen
Dim h2 As HierarchyItem = h1.Subitems.AddItem(dr.Item("Employee"))
h2.AddField("L2_Employee", dr.Item("Employee"))
h2.AddField("L2_Budget", dr.Item("Budget"))
Next
Die geschachtelten Repeater
Der Code der WebForm ist ebenfalls recht simpel:
<asp:Repeater ID="rptLevel1" runat="server">
<ItemTemplate>
<h2><%#Container.DataItem.Field("L1_Month").Value%></h2>
<table>
<asp:Repeater ID="rptLevel2" runat="server"
DataSource='<%#Container.DataItem.SubItems.Items%>'>
<ItemTemplate>
<tr>
<td><%#Container.DataItem.Field("L2_Employee").Value%></td>
<td><%#Container.DataItem.Field("L2_Budget").Value%></td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</ItemTemplate>
</asp:Repeater>
Hauptaugenmerk liegt dabei auf den beiden ineinander geschachtelten Repeatern und der DataSource-Definition des inneren, denn
hier wird lediglich das SubItem-Element des übergeordneten Items gebunden. Dies bedeutet, dass die Bindung des ersten Repeaters
ausreicht, um das komplette Konstrukt auszugeben.
Me.rptLevel1.DataSource = h.Items
Me.rptLevel1.DataBind()
Wie man sieht, muss es nicht immer LINQ sein. Auch mit Standard-Generics kommt man schnell, einfach und vor allem übersichtlich ans Ziel.
Happy coding :)
Downloads
HierarchyObject.zip