VB.NET Dapper – Micro ORM für sauberen Datenzugriff (2026)

Dapper ist der schnellste Weg, um das mühsame SqliteCommand-Boilerplate in deiner VB.NET-Anwendung durch sauberen, typsicheren Datenzugriff zu ersetzen. In diesem Guide zeige ich dir, wie du Dapper per NuGet installierst, Abfrageergebnisse direkt auf Klassen mappst und alle CRUD-Operationen mit minimalem Code ausführst. Wenn du bisher AddWithValue und ExecuteReader von Hand geschrieben hast, ist das hier dein nächster Schritt.

Datenbank-Hilfe gesucht?

ADO.NET-Boilerplate ohne Ende?

Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Ob Dapper, EF Core oder Raw SQL – ich helfe dir, die richtige Data-Access-Strategie zu finden.

Was ist Dapper und warum lohnt es sich?

Dapper ist ein leichtgewichtiger „Micro ORM“ für .NET, der ursprünglich vom Stack Overflow-Team entwickelt wurde, um deren eigene Performance-Probleme zu lösen. Er setzt auf IDbConnection auf und erweitert es mit praktischen Methoden wie Query(Of T) und Execute(). Hier ist, warum das relevant ist:

  • Kein Boilerplate – kein manuelles SqliteCommand, AddWithValue, ExecuteReader und spaltenweises Mapping mehr
  • Stark typisiert – Abfrageergebnisse werden direkt auf deine VB.NET-Klassen gemappt, anhand übereinstimmender Property-Namen
  • Schnell – Dapper ist fast so schnell wie reines ADO.NET, deutlich schneller als Entity Framework bei einfachen Abfragen
  • Keine Magie – du schreibst echtes SQL, also weißt du immer genau, was an die Datenbank geht
  • Funktioniert mit jeder Datenbank – SQLite, SQL Server, PostgreSQL, MySQL, alles was eine IDbConnection hat

Wenn du den VB.NET SQLite Artikel gelesen hast, kennst du bereits die Grundlagen: Datenbank erstellen und Abfragen mit SqliteCommand ausführen. Dapper ersetzt diese manuelle Arbeit, während du die volle Kontrolle über dein SQL behältst.

Dapper per NuGet installieren

Öffne die Package Manager Console in Visual Studio (Tools → NuGet Package Manager → Package Manager Console) und führe aus:

Install-Package Dapper
Install-Package Microsoft.Data.Sqlite

Du brauchst beide Pakete: Dapper liefert die Extension Methods, Microsoft.Data.Sqlite die Datenbank-Verbindung. Wenn du Microsoft.Data.Sqlite aus einem früheren Projekt bereits installiert hast, reicht es, nur Dapper hinzuzufügen.

Alternativ: Rechtsklick auf das Projekt im Solution Explorer → NuGet-Pakete verwalten → nach Dapper suchen → Installieren. Dann für Microsoft.Data.Sqlite wiederholen, falls noch nicht vorhanden.

Die Model-Klasse anlegen

Bevor du Abfragen schreibst, definiere eine Klasse, deren Properties den Spaltennamen in deiner Tabelle entsprechen. Dapper mappt Spalten auf Properties anhand des Namens (Groß-/Kleinschreibung egal):

Public Class Contact
    Public Property Id As Long
    Public Property Name As String
    Public Property Email As String
    Public Property Phone As String
    Public Property CreatedAt As String
End Class

Das ist alles, was Dapper braucht. Keine Attribute, keine Basisklassen, keine Konfigurationsdateien. Wenn ein Spaltenname nicht zum Property-Namen passt, verwende einen SQL-Alias: SELECT first_name AS Name.

Verbindung herstellen und Tabellen erstellen

Dapper arbeitet auf Basis von IDbConnection. Die Verbindung erstellst du weiterhin selbst. Verwende AppContext.BaseDirectory für einen zuverlässigen Pfad, wie im Application Path Artikel beschrieben:

Imports Dapper
Imports Microsoft.Data.Sqlite

Dim dbPath As String = Path.Combine(AppContext.BaseDirectory, "myapp.db")
Dim connectionString As String = $"Data Source={dbPath}"

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute("
        CREATE TABLE IF NOT EXISTS Contacts (
            Id INTEGER PRIMARY KEY AUTOINCREMENT,
            Name TEXT NOT NULL,
            Email TEXT,
            Phone TEXT,
            CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
        )")
End Using

Beachte, wie connection.Execute() das gesamte SqliteCommand– / ExecuteNonQuery()-Pattern ersetzt. Dapper öffnet die Verbindung automatisch, wenn sie geschlossen ist, aber ich bevorzuge es, sie explizit zu öffnen.

Daten einfügen (INSERT)

Mit rohem ADO.NET würdest du einen Command erstellen, Parameter einzeln hinzufügen und ExecuteNonQuery() aufrufen. Mit Dapper übergibst du ein anonymes Objekt und die Properties werden automatisch auf die Parameter gemappt:

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute(
        "INSERT INTO Contacts (Name, Email, Phone) VALUES (@Name, @Email, @Phone)",
        New With {
            .Name = "Max Mustermann",
            .Email = "max@example.com",
            .Phone = "+49 123 456789"
        })
End Using

Dapper erzeugt automatisch parametrisierte Abfragen aus dem anonymen Objekt. Es besteht kein Risiko für SQL Injection, da die Werte nie in den SQL-String konkateniert werden.

Mehrere Zeilen auf einmal einfügen

Übergib eine Liste statt eines einzelnen Objekts und Dapper führt das Statement einmal pro Element aus:

Dim contacts As New List(Of Contact) From {
    New Contact With {.Name = "Alice", .Email = "alice@example.com"},
    New Contact With {.Name = "Bob", .Email = "bob@example.com"},
    New Contact With {.Name = "Clara", .Email = "clara@example.com"}
}

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute(
        "INSERT INTO Contacts (Name, Email) VALUES (@Name, @Email)",
        contacts)
End Using

Bei großen Datenmengen (Hunderte oder Tausende Zeilen) solltest du das in einer Transaktion kapseln, um die Performance deutlich zu verbessern. Dazu weiter unten mehr.

Daten abfragen (SELECT)

Hier zeigt Dapper seine wahre Stärke. Statt einen DataReader zu durchlaufen und jede Spalte manuell zu mappen, rufst du Query(Of T) auf und bekommst eine typisierte Collection zurück:

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim contacts = connection.Query(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name")

    For Each contact In contacts
        Console.WriteLine($"[{contact.Id}] {contact.Name} - {contact.Email}")
    Next
End Using

Das Ergebnis ist ein IEnumerable(Of Contact), das du iterieren, mit LINQ filtern oder direkt an ein DataGridView binden kannst.

Abfragen mit Parametern

Parameter übergibst du wie bei Execute() als anonymes Objekt:

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim results = connection.Query(Of Contact)(
        "SELECT Id, Name, Email FROM Contacts WHERE Name LIKE @Search",
        New With {.Search = $"%{searchTerm}%"})

    For Each contact In results
        Console.WriteLine($"[{contact.Id}] {contact.Name}")
    Next
End Using

Einzelne Zeile abfragen

Verwende QueryFirstOrDefault(Of T), wenn du genau ein Ergebnis erwartest (oder keines):

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim contact = connection.QueryFirstOrDefault(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts WHERE Id = @Id",
        New With {.Id = 1})

    If contact IsNot Nothing Then
        Console.WriteLine($"{contact.Name} ({contact.Email})")
    End If
End Using

Weitere Varianten: QueryFirst (Exception wenn keine Zeilen), QuerySingle (Exception wenn nicht genau eine Zeile), QuerySingleOrDefault (Exception wenn mehr als eine Zeile).

Skalare Abfragen

Für Abfragen, die einen einzelnen Wert zurückgeben, verwende ExecuteScalar(Of T):

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim count = connection.ExecuteScalar(Of Long)(
        "SELECT COUNT(*) FROM Contacts")

    Console.WriteLine($"{count} Kontakte in der Datenbank")
End Using
Projekt in Planung?

Brauchst du eine saubere Data-Access-Schicht?

Von SQLite bis SQL Server, von rohem ADO.NET bis Dapper: Ich entwerfe Datenschichten, die skalieren. Lass uns über dein Projekt sprechen.

Daten aktualisieren und löschen

Updates und Deletes folgen dem gleichen Muster wie Inserts. Execute() gibt die Anzahl betroffener Zeilen zurück:

UPDATE

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim rowsAffected = connection.Execute(
        "UPDATE Contacts SET Email = @Email WHERE Id = @Id",
        New With {.Email = "neue-email@example.com", .Id = 1})

    Console.WriteLine($"{rowsAffected} Zeile(n) aktualisiert.")
End Using

DELETE

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim rowsAffected = connection.Execute(
        "DELETE FROM Contacts WHERE Id = @Id",
        New With {.Id = 5})

    Console.WriteLine($"{rowsAffected} Zeile(n) gelöscht.")
End Using

Komplettes Beispiel: ContactRepository mit Dapper

Hier ist eine vollständige Repository-Klasse für alle CRUD-Operationen. Vergleiche sie mit der manuellen ADO.NET-Version im SQLite-Artikel, um zu sehen, wie viel Code Dapper einspart:

Imports Dapper
Imports Microsoft.Data.Sqlite

Public Class ContactRepository

    Private ReadOnly _connectionString As String

    Public Sub New(connectionString As String)
        _connectionString = connectionString
    End Sub

    Public Sub InitializeDatabase()
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            connection.Execute("
                CREATE TABLE IF NOT EXISTS Contacts (
                    Id INTEGER PRIMARY KEY AUTOINCREMENT,
                    Name TEXT NOT NULL,
                    Email TEXT,
                    Phone TEXT,
                    CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
                )")
        End Using
    End Sub

    Public Function AddContact(name As String, email As String, phone As String) As Long
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            connection.Execute(
                "INSERT INTO Contacts (Name, Email, Phone) VALUES (@Name, @Email, @Phone)",
                New With {.Name = name, .Email = email, .Phone = phone})

            Return connection.ExecuteScalar(Of Long)("SELECT last_insert_rowid()")
        End Using
    End Function

    Public Function GetAllContacts() As List(Of Contact)
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Return connection.Query(Of Contact)(
                "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name").AsList()
        End Using
    End Function

    Public Function GetContactById(id As Long) As Contact
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Return connection.QueryFirstOrDefault(Of Contact)(
                "SELECT Id, Name, Email, Phone FROM Contacts WHERE Id = @Id",
                New With {.Id = id})
        End Using
    End Function

    Public Function UpdateContact(id As Long, name As String, email As String, phone As String) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Dim rows = connection.Execute(
                "UPDATE Contacts SET Name = @Name, Email = @Email, Phone = @Phone WHERE Id = @Id",
                New With {.Name = name, .Email = email, .Phone = phone, .Id = id})
            Return rows > 0
        End Using
    End Function

    Public Function DeleteContact(id As Long) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Dim rows = connection.Execute(
                "DELETE FROM Contacts WHERE Id = @Id",
                New With {.Id = id})
            Return rows > 0
        End Using
    End Function
End Class

Die Verwendung ist unkompliziert:

Dim repo As New ContactRepository($"Data Source={dbPath}")
repo.InitializeDatabase()

Dim newId = repo.AddContact("Max Mustermann", "max@example.com", "+49 123 456789")
Console.WriteLine($"Kontakt mit ID {newId} erstellt")

Dim allContacts = repo.GetAllContacts()
For Each c In allContacts
    Console.WriteLine($"[{c.Id}] {c.Name} - {c.Email}")
Next

Transaktionen mit Dapper

Bei Bulk-Operationen solltest du eine Transaktion verwenden. Ohne Transaktion führt SQLite nach jedem einzelnen Statement einen Commit durch, was bei Hunderten von Inserts extrem langsam wird:

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Using transaction = connection.BeginTransaction()
        Dim contacts As New List(Of Object)
        For i As Integer = 1 To 1000
            contacts.Add(New With {
                .Name = $"Kontakt {i}",
                .Email = $"kontakt{i}@example.com"
            })
        Next

        connection.Execute(
            "INSERT INTO Contacts (Name, Email) VALUES (@Name, @Email)",
            contacts,
            transaction)

        transaction.Commit()
    End Using
End Using

Der entscheidende Unterschied zu rohem ADO.NET: Du übergibst das transaction-Objekt als Parameter an Execute(). Kein manuelles command.Transaction setzen. Und weil Dapper die Liste intern durchläuft, bekommst du Transaktionssicherheit für alle 1000 Inserts mit minimalem Code.

Async-Abfragen: GUI nicht einfrieren

Jede Dapper-Methode hat ein asynchrones Pendant. Wenn du eine WinForms- oder WPF-Anwendung baust, verwende sie, damit die Oberfläche während der Datenbankaufrufe nicht einfriert. Die Grundlagen findest du im VB.NET Async/Await Guide.

Private Async Function LoadContactsAsync() As Task(Of List(Of Contact))
    Using connection As New SqliteConnection(connectionString)
        Await connection.OpenAsync()

        Dim contacts = Await connection.QueryAsync(Of Contact)(
            "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name")

        Return contacts.AsList()
    End Using
End Function

Verfügbare Async-Methoden: QueryAsync, QueryFirstOrDefaultAsync, ExecuteAsync, ExecuteScalarAsync. Sie funktionieren genau wie ihre synchronen Gegenstücke, nur mit Await.

Dapper vs. ADO.NET: Direktvergleich

Hier die gleiche „alle Kontakte laden“-Operation auf beide Arten. Zuerst reines ADO.NET, wie im SQLite-Artikel gezeigt:

' Reines ADO.NET - 13 Zeilen
Using connection As New SqliteConnection(connectionString)
    connection.Open()
    Using command As New SqliteCommand("SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name", connection)
        Using reader = command.ExecuteReader()
            While reader.Read()
                Dim contact As New Contact With {
                    .Id = reader.GetInt64(0),
                    .Name = reader.GetString(1),
                    .Email = If(reader.IsDBNull(2), "", reader.GetString(2)),
                    .Phone = If(reader.IsDBNull(3), "", reader.GetString(3))
                }
                contacts.Add(contact)
            End While
        End Using
    End Using
End Using

Und jetzt das gleiche mit Dapper:

' Dapper - 4 Zeilen
Using connection As New SqliteConnection(connectionString)
    connection.Open()
    Dim contacts = connection.Query(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name").AsList()
End Using

Gleiches Ergebnis, gleiches SQL, gleiche Performance. Dapper übernimmt die Reader-Schleife, die Null-Checks und das Property-Mapping automatisch. Je komplexer das Datenmodell, desto größer der Unterschied.

Häufige Stolperfallen und Tipps

Property-Namen müssen zu Spaltennamen passen

Dapper mappt nach Name, Groß-/Kleinschreibung wird ignoriert. Wenn deine Tabelle first_name hat, dein Property aber FirstName heißt, verwende einen SQL-Alias:

Dim contacts = connection.Query(Of Contact)(
    "SELECT first_name AS FirstName, last_name AS LastName FROM Contacts")

NULL-Werte

Dapper behandelt NULL-Spalten automatisch. Wenn eine Spalte NULL ist und das Ziel-Property ein String, wird es zu Nothing. Wenn du stattdessen einen leeren String willst, initialisiere deine Properties mit Standardwerten:

Public Class Contact
    Public Property Id As Long
    Public Property Name As String = ""
    Public Property Email As String = ""
    Public Property Phone As String = ""
End Class

Using-Blöcke nicht vergessen

Dapper verwaltet keine Verbindungs-Lebenszeiten. Du brauchst weiterhin Using-Blöcke für jede Verbindung, genau wie bei rohem ADO.NET. Eine offene Verbindung sperrt die SQLite-Datei.

Dapper und Dependency Injection

In größeren Anwendungen solltest du den Connection String per Injection übergeben statt ihn hardzucoden. Die ContactRepository-Klasse oben folgt bereits diesem Muster. Wenn du einen DI-Container wie Autofac einsetzt, schau dir den Dependency Injection Guide an.

Interessiert?

Erfahrenen .NET-Entwickler gesucht?

Ich übernehme dein Projekt, vom Datenbankdesign bis zur fertigen Anwendung. Schreib mir einfach eine Nachricht.

FAQ

Was ist Dapper in VB.NET?

Dapper ist ein leichtgewichtiger Micro ORM, der IDbConnection um Methoden wie Query(Of T) und Execute() erweitert. Er mappt SQL-Ergebnisse direkt auf VB.NET-Klassen, ohne den Overhead eines vollen ORM wie Entity Framework.

Ist Dapper schneller als Entity Framework?

Ja. Dapper ist fast so schnell wie reines ADO.NET, weil es minimalen Overhead erzeugt. Entity Framework fügt Change Tracking, Proxy-Generierung und Query-Translation hinzu, was es bei einfachen Operationen langsamer macht.

Kann ich Dapper mit SQLite in VB.NET verwenden?

Ja. Installiere Dapper und Microsoft.Data.Sqlite per NuGet. Dapper arbeitet mit jeder IDbConnection, also funktioniert SqliteConnection ohne weitere Konfiguration.

Wie gehe ich mit NULL-Werten bei Dapper um?

Dapper mappt NULL-Spalten auf Nothing bei Referenztypen. Wenn du leere Strings bevorzugst, initialisiere deine Properties mit Standardwerten wie Public Property Email As String = "".

Unterstützt Dapper Async/Await?

Ja. Jede Dapper-Methode hat ein asynchrones Gegenstück: QueryAsync, ExecuteAsync, ExecuteScalarAsync usw. Verwende sie mit Await in WinForms- oder WPF-Anwendungen, um die Oberfläche reaktionsfähig zu halten.

Fazit

Dapper eliminiert das repetitive ADO.NET-Boilerplate, während du die volle Kontrolle über dein SQL behältst. Installiere das NuGet-Paket, definiere eine Model-Klasse und ersetze dein manuelles SqliteCommand– / DataReader-Code durch Query(Of T) und Execute(). Wenn du deine Datenbank noch nicht aufgesetzt hast, starte zuerst mit dem VB.NET SQLite Guide und komm dann hierher zurück, um deine Datenzugriffsschicht zu vereinfachen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Robert Skibbe
Datenschutz-Übersicht

Diese Website verwendet Cookies, damit wir dir die bestmögliche Benutzererfahrung bieten können. Cookie-Informationen werden in deinem Browser gespeichert und führen Funktionen aus, wie das Wiedererkennen von dir, wenn du auf unsere Website zurückkehrst, und hilft unserem Team zu verstehen, welche Abschnitte der Website für dich am interessantesten und nützlichsten sind.