25.4 Tabellenzuordnung mit TableMappings
Um ein DataSet mit mehreren Tabellen zu füllen, können Sie eine Batch-Abfrage absetzen:
Dim strSQL As String = _ "SELECT * FROM Products;SELECT * FROM Suppliers;SELECT * FROM Categories" Dim da As DbDataAdapter = New SqlDataAdapter(strSQL, con) Dim ds As DataSet = New DataSet() da.Fill(ds)
Das DataSet enthält nun drei Tabellen. In jeder sind alle Datensätze der Originaltabellen Products, Suppliers und Categories enthalten. Wie können Sie eine bestimmte Tabelle im DataSet ansprechen, wenn darin mehrere Tabellen enthalten sind?
Ein DataSet verwaltet in der Eigenschaft Tables alle in ihm enthaltenen Tabellen in einer Auflistung vom Typ DataTableCollection.
Public ReadOnly Property Tables As DataTableCollection |
Jedes DataTable-Objekt speichert seinen Tabellennamen in der Eigenschaft TableName. Mit diesen Kenntnissen können wir jetzt die Namen der Tabellen im DataSet abfragen.
For Each table As DataTable In ds.Tables Console.WriteLine(table.TableName) Next
Die Ausgabe wird nicht – wie vielleicht zu vermuten wäre – Products, Supplieres und Categories lauten, sondern, wie schon vorher behauptet:
Table Table1 Table2
Die Zuordnung von Table zu Products, Table1 zu Suppliers und Table2 zu Categories ist aber in den meisten Fällen nicht wünschenswert. Besser geeignet wären sprechende Bezeichner, die zur Lesbarkeit des Programmcodes beitragen. Der DataAdapter bietet daher einen Mechanismus, um den Tabellen im Abfrageergebnis einen anderen Namen zuzuordnen: die Eigenschaft TableMappings, die die Referenz auf ein DataTableMappingCollection-Objekt liefert.
Public ReadOnly Property TableMappings As DataTableMappingCollection |
Jedes DataTableMapping-Objekt einer DataTableMappingCollection ordnet einer Tabelle im DataSet einen Tabellennamen zu. Die Auflistung ist einfach mit der Add-Methode zu füllen. Der erste Parameter spezifiziert den Namen der Tabelle innerhalb von DataSet, der zweite gibt den neuen Namen an.
Public Function Add(sourceTable As String, dataSetTable As String) _
As DataTableMapping |
Das folgende Codefragment zeigt, wie Sie die DataTableMappingCollection eines DataAdapter-Objekts füllen können. Wir verwenden dieselbe Batch-Abfrage wie oben. Die Zuordnung muss vor dem Füllen des DataSets mit Fill erfolgen, sonst bleibt sie wirkungslos.
Dim strSQL As String = _
"SELECT * FROM Products;SELECT * FROM Suppliers;SELECT * FROM Categories"
Dim da As DbDataAdapter = new SqlDataAdapter(strSQL, con)
da.TableMappings.Add("Table", "Artikel")
da.TableMappings.Add("Table1", "Lieferanten")
da.TableMappings.Add("Table2", "Kategorien")
Dim ds As DataSet = new DataSet()
da.Fill(ds)
...
Add ruft implizit den DataTableMapping-Konstruktor auf. Sie können das natürlich auch selbst in die Hand nehmen, müssen dann aber jeder Tabelle über die Eigenschaft SourceTable sagen, welchen Standardnamen sie im DataSet hat, und über DataSetTable mitteilen, welcher Bezeichner der Tabelle neu zugeordnet werden soll. Das folgende Beispiel zeigt, wie der Code dazu aussieht:
Dim dtm1 As DataTableMapping = New DataTableMapping()
dtm1.SourceTable = "Table"
dtm1.DataSetTable = "Artikel"
da.TableMappings.Add(dtm1)
Dim dtm2 As DataTableMapping = New DataTableMapping()
dtm2.SourceTable = "Table1"
dtm2.DataSetTable = "Lieferanten"
da.TableMappings.Add(dtm2)
Dim dtm3 as DataTableMapping = New DataTableMapping()
dtm3.SourceTable = "Table2"
dtm3.DataSetTable = "Kategorien"
da.TableMappings.Add(dtm3)
Dim ds As DataSet = New DataSet()
da.Fill(ds)
...
Die Klasse DataTableMapping gehört zum Namensraum System.Data.Common, der vorher mit Imports bekannt gegeben werden sollte. Deutlich ist zu sehen, dass diese Art der Zuordnung mehr Programmieraufwand bedeutet.
25.4.1 Spaltenzuordnungen in einem DataSet
Jeder Spalte der SELECT-Abfrage wird eine Spalte in der DataTable zugeordnet. Als Spaltenbezeichner verwendet ADO.NET dabei den Spaltennamen der Originaltabelle in der Datenbank. Fragen Sie die Datenquelle mit
SELECT ProductName, UnitPrice FROM Products
ab, lauten die Spalten in der DataTable ebenfalls ProductName und UnitPrice. Wünschen Sie andere Spaltenbezeichner, können Sie im SELECT-Statement für die einzelnen Spalten einen Alias angeben, zum Beispiel:
SELECT ProductName AS Artikelname, UnitPrice As Einzelpreis FROM Products
Nun lauten in der DataTable die Spaltenbezeichner Artikelname und Einzelpreis.
Sie können alternativ einen anderen Mechanismus einsetzen. Ein DataTableMapping-Objekt hat eine eigene Auflistung, mit der den vordefinierten Spaltenbezeichnern neue zugeordnet werden können. Diese Auflistung ist vom Typ DataColumnMappingCollection und enthält DataColumnMapping-Objekte. Jedes DataColumnMapping-Objekt beschreibt für sich eine Neuzuordnung eines Spaltenbezeichners in einer DataTable. Die ein wenig komplex anmutenden Zusammenhänge zwischen DataAdapter, DataTableMapping und DataColumnMapping sind in Abbildung 25.1 dargestellt.
Abbildung 25.1 Hierarchie der Zuordnungsklassen
Die Referenz auf die DataColumnMappingCollection stellt die Eigenschaft ColumnMappings der Klasse DataTableMapping bereit:
Public ReadOnly Property ColumnMappings As DataColumnMappingCollection |
Um eine Neuzuordnung festzulegen, bietet sich auch hier der Weg über die Add-Methode des DataColumnMappingCollection-Objekts an:
Public Function Add(sourceColumn As String, dataSetColumn As String) _
As DataColumnMapping |
Analog zur Add-Methode der DataTableMappingCollection wird dem ersten Parameter der ursprüngliche Spaltenbezeichner und dem zweiten Parameter der neue Spaltenbezeichner übergeben.
Das folgende Codefragment zeigt den Code, der notwendig ist, um neben dem Tabellennamen auch die Spaltenbezeichner einer Abfrage neu festzulegen. Zum Schluss werden die Spaltenneuzuordnungen zur Bestätigung an der Konsole ausgegeben. Der Code im Schleifenkopf zur Ausgabe der Spaltenbezeichner dürfte auch ohne weitere Erläuterungen verständlich sein.
'...\ADO\DataAdapter\Mapping.vb |
Option Strict On Imports System.Data.Common, System.Data.SqlClient Namespace ADO Module Mapping Sub Test() Dim con As DbConnection = New SqlConnection() con.ConnectionString = "Data Source=(local);" & _ "Initial Catalog=Northwind;Integrated Security=sspi" Dim cmd As DbCommand = New SqlCommand() cmd.CommandText = "SELECT ProductName, UnitPrice FROM products" cmd.Connection = con Dim da As DbDataAdapter = New SqlDataAdapter() da.SelectCommand = cmd ' Neuzuordnung des Tabellennamens Dim dtm As DataTableMapping = da.TableMappings.Add("Table", "Artikel") ' Neuzuordnung der Spaltenbezeichner dtm.ColumnMappings.Add("ProductName", "Artikelname") dtm.ColumnMappings.Add("UnitPrice", "Einzelpreis") ' lokaler Speicher Dim ds As New DataSet() da.Fill(ds) ' Bezeichner ausgeben Console.WriteLine("Tabelle {0}", ds.Tables(0).TableName) For Each col As DataColumn In ds.Tables(0).Columns Console.WriteLine("Spalte {0} ", col.ColumnName) Next Console.ReadLine() End Sub End Module End Namespace
25.4.2 Spaltenzuordnungen einer DataTable
Übergeben Sie der Fill-Methode anstelle eines DataSet-Objekts ein DataTable-Objekt, müssen Sie ein wenig anders vorgehen, um die Spalten mit eigenen Bezeichnern im lokalen Datenspeicher anzusprechen. Dazu erzeugen Sie auch wieder ein DataTableMapping-Objekt, dem Sie die gewünschten Spaltenbezeichner zuordnen. Bei der Instanziierung von DataTable rufen Sie allerdings den parametrisierten Konstruktor auf, dem der im DataTableMappping zugeordnete Tabellenname übergeben wird.
... Dim dtm As DataTableMapping = da.TableMappings.Add("Table", "Artikel") ' Neuzuordnung der Spaltenbezeichner dtm.ColumnMappings.Add("ProductName", "Artikelname") dtm.ColumnMappings.Add("UnitPrice", "Einzelpreis") Dim tbl As DataTable = New DataTable("Artikel") da.Fill(tbl) ...
25.4.3 Die Eigenschaft MissingMappingAction des DataAdapters
Die Neuzuordnung der Tabellen- und Spaltenbezeichner ist eine Option, die vor dem Aufruf der Methode Fill wahrgenommen werden kann oder nicht. Der DataAdapter prüft vor dem Füllen des DataSets, ob die Zuordnungsauflistungen gefüllt sind. Dabei interessiert er sich besonders für die Spaltenzuordnungen.
Für jede Spalte des Abfrageergebnisses überprüft der DataAdapter, ob dafür eine Zuordnung in der DataColumnMappingCollection angegeben ist. Existiert sie nicht, überprüft er im nächsten Schritt seine MissingMappingAction-Eigenschaft, die vom Typ der gleichnamigen Enumeration ist (siehe Tabelle 25.1). Ihr Standardwert sorgt dafür, dass die Spaltennamen der Originaltabelle in die DataTable übernommen werden. Alternativ kann der DataAdapter angewiesen werden, alle Spalten zu ignorieren, die nicht in der Zuordnungstabelle enthalten sind. Eine dritte Möglichkeit ist die Auslösung einer Ausnahme, wenn keine Zuordnung angegeben ist.
Konstante | Effekt bei fehlender Spaltenzuordnung |
Error |
Eine Ausnahme wird ausgelöst. |
Ignore |
Die Spalte in der DataTable wird ignoriert. |
Passthrough |
Die Spalte wird unter ihrem ursprünglichen Namen der DataTable hinzugefügt (Standard). |
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.