VB.NET DataTable – Erstellen, Füllen, Filtern (2026)
Die VB.NET DataTable speichert tabellarische Daten im Arbeitsspeicher, mit typisierten Spalten, zeilenweisem Zugriff und eingebautem Filtern. Sie ist das Rückgrat der Datenbindung in WinForms und die Brücke zwischen Datenbank und UI-Controls wie dem DataGridView. Dieser Guide behandelt Erstellung, Filtern, Sortieren, Datenbankanbindung und die häufigsten Fehler.
Inhaltsverzeichnis
- 1 Was ist eine DataTable und wann setzt man sie ein?
- 2 Eine DataTable mit Spalten erstellen
- 3 Zeilen hinzufügen
- 4 Daten lesen und zugreifen
- 5 Filtern mit Select und DataView
- 6 Zeilen sortieren
- 7 Zeilen aktualisieren und löschen
- 8 DataTable an ein DataGridView binden
- 9 Daten aus einer Datenbank laden
- 10 Konvertierung zwischen DataTable und List
- 11 Häufige Stolperfallen
- 12 FAQ
- 13 Fazit
Was ist eine DataTable und wann setzt man sie ein?
Eine DataTable liegt im System.Data-Namespace und stellt eine einzelne Tabelle im Arbeitsspeicher dar. Vergleichbar mit einer Tabellenkalkulation: sie hat Spalten mit Namen und Typen, und Zeilen, die die eigentlichen Werte enthalten.
Verwende eine DataTable, wenn:
- Du tabellarische Daten an ein DataGridView oder andere WinForms-Controls binden willst
- Du mit ADO.NET arbeitest und eine Tabelle aus einer Datenbankabfrage füllen willst
- Du eingebautes Filtern und Sortieren brauchst, ohne eigene Logik schreiben zu müssen
- Du CSV- oder Excel-Importe verarbeitest, bei denen Zeilen und Spalten natürlich abbildbar sind
Falls du nur eine geordnete Liste von Objekten brauchst, ist eine VB.NET List(Of T) einfacher und typsicherer. Für Key-Value-Lookups verwende ein Dictionary. Die DataTable spielt ihre Stärken aus, wenn du eine flexible, schemabasierte Struktur mit Filtern, Sortieren und UI-Binding brauchst.
Eine DataTable mit Spalten erstellen
Jede DataTable beginnt mit einem Schema: den Spalten, die festlegen, welche Daten jede Zeile aufnehmen kann.
Dim table As New DataTable("Contacts")
' Spalten mit Name und Typ hinzufügen
table.Columns.Add("Id", GetType(Integer))
table.Columns.Add("Name", GetType(String))
table.Columns.Add("Email", GetType(String))
table.Columns.Add("Age", GetType(Integer))
' Primärschlüssel setzen
table.PrimaryKey = {table.Columns("Id")}
Jede Spalte hat einen DataType (Integer, String, DateTime, Decimal, Boolean, etc.) und einen optionalen ColumnName. Der Primärschlüssel ermöglicht schnelle Lookups mit Rows.Find() und verhindert doppelte Einträge.
Spalteneigenschaften
' Auto-Increment Spalte
Dim idCol = table.Columns("Id")
idCol.AutoIncrement = True
idCol.AutoIncrementSeed = 1
idCol.AutoIncrementStep = 1
' Standardwert
table.Columns("Age").DefaultValue = 0
' Nullwerte verbieten
table.Columns("Name").AllowDBNull = False
Zeilen hinzufügen
' Methode 1: NewRow + Felder zuweisen
Dim row As DataRow = table.NewRow()
row("Name") = "Alice"
row("Email") = "alice@example.com"
row("Age") = 30
table.Rows.Add(row)
' Methode 2: Werte direkt übergeben (Spaltenreihenfolge)
table.Rows.Add(Nothing, "Bob", "bob@example.com", 25)
' Methode 3: Aus einem Object-Array
Dim values() As Object = {Nothing, "Clara", "clara@example.com", 35}
table.Rows.Add(values)
Bei einer AutoIncrement-Id-Spalte übergibst du Nothing für das Feld. Die DataTable vergibt den nächsten Wert automatisch.
Daten lesen und zugreifen
' Auf eine bestimmte Zeile per Index zugreifen
Dim firstRow As DataRow = table.Rows(0)
Dim name As String = CStr(firstRow("Name"))
' Alle Zeilen durchlaufen
For Each row As DataRow In table.Rows
Console.WriteLine($"{row("Id")}: {row("Name")} ({row("Email")})")
Next
' Zeile per Primärschlüssel finden
Dim found As DataRow = table.Rows.Find(2)
If found IsNot Nothing Then
Console.WriteLine($"Gefunden: {found("Name")}")
End If
' Gesamtanzahl der Zeilen
Dim count As Integer = table.Rows.Count
Felder geben Object zurück, daher musst du sie casten (CStr, CInt, CDec, etc.) oder die typisierte Field(Of T)-Erweiterungsmethode verwenden: row.Field(Of String)("Name"). Die Field-Methode behandelt DBNull bei Nullable-Typen automatisch sicher.
Filtern mit Select und DataView
DataTable bietet zwei Wege zum Filtern: die Select()-Methode für schnelle Abfragen und DataView für persistente, bindbare Filter.
DataTable.Select()
' Nach Bedingung filtern
Dim olderThan25() As DataRow = table.Select("Age > 25")
' Filtern + sortieren
Dim sorted() As DataRow = table.Select("Age > 25", "Name ASC")
' Mehrere Bedingungen
Dim specific() As DataRow = table.Select("Age > 20 AND Name LIKE 'A%'")
' Ergebnisse verarbeiten
For Each row In olderThan25
Console.WriteLine(row("Name"))
Next
Der Filterausdruck nutzt eine SQL-ähnliche Syntax: =, <>, >, <, LIKE, AND, OR, IN, IS NULL. Der Sortierausdruck nimmt einen Spaltennamen gefolgt von ASC oder DESC.
DataView für bindbares Filtern
Eine DataView umschließt eine DataTable und liefert eine gefilterte, sortierte Sicht, die direkt an UI-Controls gebunden werden kann:
Dim view As New DataView(table) view.RowFilter = "Age >= 30" view.Sort = "Name ASC" ' An DataGridView binden DataGridView1.DataSource = view ' Filter zur Laufzeit ändern (UI aktualisiert sich automatisch) view.RowFilter = "Name LIKE 'B%'"
DataView ist die bessere Wahl für eine DataGridView-Filterfunktion, weil sie das gebundene Control automatisch aktualisiert, wenn RowFilter oder Sort geändert werden.
Zeilen sortieren
Die DataTable selbst hat keine Sort()-Methode. Sortiert wird über Select() oder DataView:
' Sortieren mit Select (gibt DataRow-Array zurück)
Dim sortedRows() As DataRow = table.Select("", "Age DESC")
' Sortieren mit DataView (bindbar)
Dim view As New DataView(table)
view.Sort = "Name ASC, Age DESC"
' Sortieren mit LINQ (gibt neue Collection zurück)
Dim linqSorted = From row In table.AsEnumerable()
Order By row.Field(Of String)("Name")
Select row
Für DataGridView-Binding verwende DataView. Zum Verarbeiten von Zeilen im Code funktionieren die Select()-Methode und LINQ gleich gut.
Zeilen aktualisieren und löschen
' Feld aktualisieren
table.Rows(0)("Email") = "alice.new@example.com"
' Per Primärschlüssel aktualisieren
Dim target As DataRow = table.Rows.Find(2)
If target IsNot Nothing Then
target("Age") = 26
End If
' Zeile löschen (markiert sie als gelöscht)
table.Rows(0).Delete()
' Zeile sofort entfernen
table.Rows.Remove(table.Rows(0))
' Alle ausstehenden Änderungen übernehmen
table.AcceptChanges()
Wichtiger Unterschied: Delete() markiert die Zeile mit RowState = Deleted, behält sie aber in der Tabelle, bis AcceptChanges() aufgerufen wird. Remove() löscht die Zeile sofort. Verwende Delete(), wenn du Change Tracking brauchst (z.B. beim Zurückschreiben in die Datenbank mit einem DataAdapter).
DataTable an ein DataGridView binden
Einer der häufigsten Einsatzzwecke einer DataTable ist die Anzeige in einem DataGridView:
' Direkte Bindung DataGridView1.DataSource = table ' Bindung über DataView (mit Filter + Sortierung) Dim view As New DataView(table) view.RowFilter = "Age > 25" view.Sort = "Name ASC" DataGridView1.DataSource = view
Das DataGridView generiert die Spalten automatisch aus dem DataTable-Schema. Änderungen im Grid werden automatisch in die DataTable zurückgeschrieben. Für ein schreibgeschütztes Grid setze DataGridView1.ReadOnly = True.
Grid nach Datenänderungen aktualisieren
' Zeile programmatisch hinzufügen table.Rows.Add(Nothing, "David", "david@example.com", 28) ' Grid aktualisiert sich automatisch bei gebundener DataTable ' Kein manuelles Refresh nötig ' Wenn du die gesamte DataTable austauschst, binde sie neu DataGridView1.DataSource = Nothing DataGridView1.DataSource = newTable
Daten aus einer Datenbank laden
DataTable funktioniert mit jedem ADO.NET-Provider. Hier ein Beispiel mit SQLite:
Imports System.Data.SQLite
Dim table As New DataTable()
Using connection As New SQLiteConnection("Data Source=app.db")
connection.Open()
Using command As New SQLiteCommand("SELECT * FROM Contacts", connection)
Using reader As SQLiteDataReader = command.ExecuteReader()
table.Load(reader)
End Using
End Using
End Using
' table enthält jetzt alle Zeilen der Contacts-Tabelle
DataGridView1.DataSource = table
Die Load()-Methode liest alle Zeilen aus einem DataReader und erstellt die Spalten automatisch anhand des Abfrageergebnisses. Das funktioniert mit SQL Server, MySQL, PostgreSQL und jedem anderen ADO.NET-Provider.
Alternative: DataAdapter verwenden
Dim table As New DataTable()
Using connection As New SQLiteConnection("Data Source=app.db")
Using adapter As New SQLiteDataAdapter("SELECT * FROM Contacts", connection)
adapter.Fill(table)
End Using
End Using
Der DataAdapter-Ansatz ist kürzer und unterstützt auch das Zurückschreiben von Änderungen in die Datenbank mit adapter.Update(table). Für einfacheren, stark typisierten Datenbankzugriff ohne DataTable ist Dapper eine Alternative.
Konvertierung zwischen DataTable und List
Manchmal muss man zwischen einer DataTable und einer typisierten List(Of T) wechseln:
DataTable zu List(Of T)
Public Class Contact
Public Property Id As Integer
Public Property Name As String
Public Property Email As String
Public Property Age As Integer
End Class
' DataTable-Zeilen in typisierte Liste konvertieren
Dim contacts = table.AsEnumerable().Select(Function(row)
Return New Contact With {
.Id = row.Field(Of Integer)("Id"),
.Name = row.Field(Of String)("Name"),
.Email = row.Field(Of String)("Email"),
.Age = row.Field(Of Integer)("Age")
}
End Function).ToList()
List(Of T) zu DataTable
Public Function ToDataTable(contacts As List(Of Contact)) As DataTable
Dim table As New DataTable()
table.Columns.Add("Id", GetType(Integer))
table.Columns.Add("Name", GetType(String))
table.Columns.Add("Email", GetType(String))
table.Columns.Add("Age", GetType(Integer))
For Each c In contacts
table.Rows.Add(c.Id, c.Name, c.Email, c.Age)
Next
Return table
End Function
Der LINQ-Ansatz mit AsEnumerable() erfordert einen Verweis auf System.Data.DataSetExtensions. Im modernen .NET (5+) ist dieser standardmäßig enthalten.
Häufige Stolperfallen
DBNull ignorieren
DataTable-Felder können DBNull.Value statt Nothing enthalten. Ein direkter Cast wirft dann eine InvalidCastException:
' SCHLECHT - wirft InvalidCastException wenn Email DBNull ist
Dim email As String = CStr(row("Email"))
' GUT - erst auf DBNull prüfen
Dim email As String = If(row.IsNull("Email"), "", CStr(row("Email")))
' OPTIMAL - typisierte Field-Erweiterung verwenden
Dim email As String = row.Field(Of String)("Email") ' gibt Nothing zurück bei DBNull
Zeilen in einer For-Each-Schleife löschen
Genau wie bei einer List wirft das Ändern einer DataTable während der Iteration eine Exception. Verwende eine rückwärts laufende For-Schleife oder sammle die Zeilen zuerst:
' SCHLECHT - Änderung während Iteration
For Each row As DataRow In table.Rows
If CInt(row("Age")) < 18 Then
row.Delete()
End If
Next
' GUT - rückwärts iterieren
For i As Integer = table.Rows.Count - 1 To 0 Step -1
If CInt(table.Rows(i)("Age")) < 18 Then
table.Rows(i).Delete()
End If
Next
table.AcceptChanges()
AcceptChanges vergessen
Wenn du Delete() auf eine Zeile aufrufst, wird sie nur als gelöscht markiert. Die Zeile erscheint weiterhin in table.Rows.Count und kann unerwartetes Verhalten verursachen. Rufe AcceptChanges() nach einer Reihe von Löschungen auf, oder verwende Remove() für sofortiges Entfernen.
FAQ
Erstelle sie mit Dim table As New DataTable(), füge Spalten hinzu mit table.Columns.Add("Name", GetType(String)) und Zeilen mit table.Rows.Add(werte). Jede Spalte braucht einen Namen und einen Datentyp.
Verwende table.Select("Age > 25") für schnelle Abfragen, die ein DataRow-Array zurückgeben. Für persistente, bindbare Filter erstelle eine DataView mit view.RowFilter = "Age > 25" und binde sie an dein DataGridView.
Setze DataGridView1.DataSource = table. Das Grid generiert die Spalten automatisch aus dem Tabellen-Schema. Für gefilterte Ansichten binde stattdessen eine DataView: DataGridView1.DataSource = New DataView(table).
Eine DataTable speichert untypisierte Zeilen mit Spalten, die zur Laufzeit definiert werden, unterstützt SQL-ähnliches Filtern und bindet nativ an DataGridView. Eine List(Of T) hält stark typisierte Objekte, ist einfacher zu nutzen, erfordert aber manuelles Filtern mit LINQ.
Verwende table.Load(reader) mit einem beliebigen ADO.NET DataReader, oder einen DataAdapter mit adapter.Fill(table). Beide Ansätze erstellen die Spalten automatisch aus dem Abfrageergebnis.
Fazit
Die DataTable ist die richtige Wahl, wenn du schemabasierte, filterbare Tabellendaten mit nativer DataGridView-Bindung brauchst. Verwende Select() für schnelle Abfragen, DataView für live-gefilterte UI-Bindung und Field(Of T) zur sicheren DBNull-Behandlung. Für einfachere Anwendungsfälle mit typisierten Objekten ist eine List(Of T) oft die bessere Wahl. Für Datenbankzugriff ohne DataTable schau dir Dapper an.