VB.NET SQLite Datenbank – Verbinden, Lesen, Schreiben (2026)

SQLite ist der einfachste Weg, eine lokale Datenbank in Deine VB.NET-Anwendung einzubauen, kein Server, keine Installation, keine Konfiguration. In diesem Guide zeige ich Dir Schritt für Schritt, wie Du SQLite per NuGet einrichtest, Tabellen anlegst und alle CRUD-Operationen mit parametrisierten Abfragen durchführst. Mit komplettem Praxisbeispiel zum Download. → Direkt zum Download.

Datenbank-Hilfe gesucht?

Du brauchst Unterstützung bei der Datenbank-Integration?

Seit über 17 Jahren entwickle ich professionell in VB.NET und C#. Ob SQLite, SQL Server oder Datenarchitektur – ich helfe Dir weiter.

Warum SQLite für Deine VB.NET-Anwendung?

Es gibt viele Datenbank-Engines, aber SQLite sticht bei lokalen VB.NET-Anwendungen besonders hervor. Die Gründe:

  • Kein Setup – kein Serverprozess, keine Installation, keine Admin-Rechte nötig
  • Eine einzige Datei – die gesamte Datenbank lebt in einer .db-Datei, die Du mit Deiner App ausliefern kannst
  • Plattformübergreifend – läuft auf Windows, Linux und macOS
  • Leichtgewichtig – perfekt für Desktop-Apps, Prototypen, Embedded-Systeme und Offline-First-Szenarien
  • Zuverlässig – wird von Firefox, Chrome, Android und Millionen anderer Anwendungen eingesetzt

Wenn Du nur Einstellungen oder kleine Datenmengen speichern möchtest, reicht es oft auch, eine Textdatei in VB.NET zu schreiben. Sobald Du aber strukturierte Daten, Abfragen oder Beziehungen brauchst, ist SQLite die bessere Wahl.

Das NuGet-Paket installieren

Es gibt zwei populäre SQLite-Pakete für .NET:

  1. Microsoft.Data.Sqlite – Microsofts offizielles, leichtgewichtiges Paket (empfohlen für .NET 5+ / .NET Framework 4.6.1+)
  2. System.Data.SQLite – das ältere, umfangreichere Paket vom SQLite-Team (unterstützt auch .NET Framework 4.0)

In diesem Artikel verwende ich Microsoft.Data.Sqlite, da es schlanker ist und der empfohlene Weg für die Zukunft. Die API ist nahezu identisch, ein späterer Wechsel ist also unkompliziert.

Installation per Package Manager Console

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

Install-Package Microsoft.Data.Sqlite

Alternativ: Rechtsklick auf das Projekt im Solution Explorer → NuGet-Pakete verwalten → nach Microsoft.Data.Sqlite suchen → Installieren.

Die Imports-Anweisung ergänzen

Am Anfang Deiner Code-Datei fügst Du folgenden Import hinzu:

Imports Microsoft.Data.Sqlite

Datenbank erstellen und verbinden

Ein großer Vorteil von SQLite: Du musst keine Datenbank manuell anlegen. Wenn die Datei noch nicht existiert, erstellt SQLite sie automatisch beim Öffnen der Verbindung.

Der Connection String

Der SQLite Connection String ist minimal. Du brauchst nur den Pfad zur Datenbankdatei:

Dim connectionString As String = "Data Source=myapp.db"

Damit wird die Datei myapp.db im Arbeitsverzeichnis der Anwendung erstellt. Wenn Du die Datenbank neben der EXE-Datei ablegen möchtest, kannst Du den VB.NET Application Path verwenden, um einen zuverlässigen Pfad zu bauen:

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

Verbindung öffnen

Packe Deine Verbindung immer in einen Using-Block. So wird die Verbindung auch bei einer Exception sauber geschlossen und freigegeben:

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    ' Deine Datenbankoperationen hier...

End Using ' Verbindung wird automatisch geschlossen

Das ist das Grundmuster für jede Datenbankoperation. Der Using-Block ist essenziell, um File-Locks und „database is locked“-Fehler zu vermeiden (dazu später mehr).

Tabellen anlegen

Bevor Du Daten speichern kannst, brauchst Du mindestens eine Tabelle. Verwende CREATE TABLE IF NOT EXISTS, damit der Befehl bei jedem App-Start sicher ausgeführt werden kann, ohne Fehler, falls die Tabelle schon existiert:

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "
            CREATE TABLE IF NOT EXISTS Contacts (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Name TEXT NOT NULL,
                Email TEXT,
                Phone TEXT,
                CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
            )"
        command.ExecuteNonQuery()
    End Using
End Using

SQLite-Datentypen

SQLite verwendet ein dynamisches Typsystem, das sich von SQL Server unterscheidet. Die gängigsten Typen sind:

  • INTEGER – Ganzzahlen (entspricht Integer / Long in VB.NET)
  • TEXT – Zeichenketten (entspricht String)
  • REAL – Gleitkommazahlen (entspricht Double)
  • BLOB – Binärdaten (entspricht Byte())
  • NULL – kein Wert

Ein Tipp: SQLite hat keinen nativen DATETIME-Typ. Speichere Datumsangaben als TEXT im ISO-8601-Format (z. B. 2026-04-07T14:30:00) oder als INTEGER (Unix-Timestamp).

Daten einfügen (INSERT)

Jetzt fügen wir einen Datensatz in unsere Contacts-Tabelle ein. Verwende immer parametrisierte Abfragen statt String-Verkettung. Das schützt Deine App vor SQL Injection und behandelt Sonderzeichen korrekt:

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "INSERT INTO Contacts (Name, Email, Phone) VALUES (@name, @email, @phone)"
        command.Parameters.AddWithValue("@name", "Max Mustermann")
        command.Parameters.AddWithValue("@email", "max@example.com")
        command.Parameters.AddWithValue("@phone", "+49 123 456789")
        command.ExecuteNonQuery()
    End Using
End Using

Warum parametrisierte Abfragen wichtig sind

Baue SQL-Strings niemals durch direktes Zusammensetzen von Benutzereingaben zusammen. Das ist der häufigste Sicherheitsfehler, der zu SQL Injection führt:

' ❌ NIEMALS so machen - SQL-Injection-Schwachstelle!
command.CommandText = "INSERT INTO Contacts (Name) VALUES ('" & txtName.Text & "')"

' ✅ Immer Parameter verwenden
command.CommandText = "INSERT INTO Contacts (Name) VALUES (@name)"
command.Parameters.AddWithValue("@name", txtName.Text)

Die zuletzt eingefügte ID abfragen

Nach dem Einfügen einer Zeile möchtest Du häufig die automatisch generierte ID wissen. Dafür gibt es last_insert_rowid():

command.CommandText = "INSERT INTO Contacts (Name, Email) VALUES (@name, @email)"
command.Parameters.AddWithValue("@name", "Erika Musterfrau")
command.Parameters.AddWithValue("@email", "erika@example.com")
command.ExecuteNonQuery()

command.CommandText = "SELECT last_insert_rowid()"
Dim newId As Long = CLng(command.ExecuteScalar())
Console.WriteLine($"Neuer Kontakt-ID: {newId}")

Daten lesen (SELECT)

Verwende ExecuteReader(), um Daten abzufragen und über die Ergebnisse zu iterieren. Auch hier: alles in Using-Blöcke verpacken:

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand("SELECT Id, Name, Email FROM Contacts", connection)
        Using reader As SqliteDataReader = command.ExecuteReader()
            While reader.Read()
                Dim id As Long = reader.GetInt64(0)
                Dim name As String = reader.GetString(1)
                Dim email As String = If(reader.IsDBNull(2), "", reader.GetString(2))

                Console.WriteLine($"[{id}] {name} - {email}")
            End While
        End Using
    End Using
End Using

Filtern mit WHERE

Um nach bestimmten Datensätzen zu suchen, verwende eine parametrisierte WHERE-Klausel:

Using command As New SqliteCommand(
    "SELECT Id, Name, Email FROM Contacts WHERE Name LIKE @search",
    connection)
    command.Parameters.AddWithValue("@search", $"%{searchTerm}%")

    Using reader As SqliteDataReader = command.ExecuteReader()
        While reader.Read()
            ' Ergebnisse verarbeiten...
        End While
    End Using
End Using

Die Ergebnisse lassen sich anschließend beispielsweise in einem VB.NET DataGridView anzeigen. Zum Speichern der Ergebnisse nach Schlüssel ist das VB.NET Dictionary eine passende Datenstruktur.

Projekt in Planung?

Du brauchst eine .NET Desktop-Anwendung mit Datenbank?

Vom Datenmodell bis zur fertigen WinForms- oder WPF-App setze ich Dein Projekt um. Lass uns über Deine Anforderungen sprechen.

Daten aktualisieren und löschen

UPDATE

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "UPDATE Contacts SET Email = @email WHERE Id = @id"
        command.Parameters.AddWithValue("@email", "neue-email@example.com")
        command.Parameters.AddWithValue("@id", 1)

        Dim rowsAffected As Integer = command.ExecuteNonQuery()
        Console.WriteLine($"{rowsAffected} Zeile(n) aktualisiert.")
    End Using
End Using

DELETE

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand("DELETE FROM Contacts WHERE Id = @id", connection)
        command.Parameters.AddWithValue("@id", 5)

        Dim rowsAffected As Integer = command.ExecuteNonQuery()
        Console.WriteLine($"{rowsAffected} Zeile(n) gelöscht.")
    End Using
End Using

Komplettes Beispiel: Kontaktverwaltung

Jetzt bringen wir alles zusammen. Hier ist eine komplette Helper-Klasse, die alle CRUD-Operationen für eine Contacts-Tabelle kapselt. Du kannst sie als Ausgangspunkt für Deine eigenen Projekte verwenden:

Imports Microsoft.Data.Sqlite

Public Class ContactRepository

    Private ReadOnly _connectionString As String

    Public Sub New(dbPath As String)
        _connectionString = $"Data Source={dbPath}"
    End Sub

    ''' Stellt sicher, dass die Contacts-Tabelle existiert.
    Public Sub InitializeDatabase()
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "
                    CREATE TABLE IF NOT EXISTS Contacts (
                        Id INTEGER PRIMARY KEY AUTOINCREMENT,
                        Name TEXT NOT NULL,
                        Email TEXT,
                        Phone TEXT,
                        CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
                    )"
                command.ExecuteNonQuery()
            End Using
        End Using
    End Sub

    ''' Fügt einen neuen Kontakt hinzu und gibt die generierte Id zurück.
    Public Function AddContact(name As String, email As String, phone As String) As Long
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "
                    INSERT INTO Contacts (Name, Email, Phone)
                    VALUES (@name, @email, @phone)"
                command.Parameters.AddWithValue("@name", name)
                command.Parameters.AddWithValue("@email", CObj(email) ?? DBNull.Value)
                command.Parameters.AddWithValue("@phone", CObj(phone) ?? DBNull.Value)
                command.ExecuteNonQuery()
            End Using

            Using command As New SqliteCommand("SELECT last_insert_rowid()", connection)
                Return CLng(command.ExecuteScalar())
            End Using
        End Using
    End Function

    ''' Gibt alle Kontakte als Liste von Dictionaries zurück.
    Public Function GetAllContacts() As List(Of Dictionary(Of String, Object))
        Dim contacts As New List(Of Dictionary(Of String, Object))

        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 As SqliteDataReader = command.ExecuteReader()
                    While reader.Read()
                        Dim contact As New Dictionary(Of String, Object) From {
                            {"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

        Return contacts
    End Function

    ''' Aktualisiert einen Kontakt anhand der Id.
    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()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "UPDATE Contacts SET Name = @name, Email = @email, Phone = @phone WHERE Id = @id"
                command.Parameters.AddWithValue("@name", name)
                command.Parameters.AddWithValue("@email", CObj(email) ?? DBNull.Value)
                command.Parameters.AddWithValue("@phone", CObj(phone) ?? DBNull.Value)
                command.Parameters.AddWithValue("@id", id)

                Return command.ExecuteNonQuery() > 0
            End Using
        End Using
    End Function

    ''' Löscht einen Kontakt anhand der Id.
    Public Function DeleteContact(id As Long) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand("DELETE FROM Contacts WHERE Id = @id", connection)
                command.Parameters.AddWithValue("@id", id)

                Return command.ExecuteNonQuery() > 0
            End Using
        End Using
    End Function

End Class

Das ContactRepository verwenden

So verwendest Du die Klasse, zum Beispiel im Form_Load-Event einer WinForms-Anwendung:

Dim dbPath As String = Path.Combine(AppContext.BaseDirectory, "contacts.db")
Dim repo As New ContactRepository(dbPath)

' Tabelle anlegen (kann bei jedem Start aufgerufen werden)
repo.InitializeDatabase()

' Kontakt hinzufügen
Dim newId As Long = repo.AddContact("Robert Skibbe", "mail@robbelroot.de", "+49 123 456")
Console.WriteLine($"Kontakt mit ID {newId} angelegt")

' Alle Kontakte auslesen
For Each contact In repo.GetAllContacts()
    Console.WriteLine($"[{contact("Id")}] {contact("Name")} - {contact("Email")}")
Next

' Kontakt aktualisieren
repo.UpdateContact(newId, "Robert S.", "neu@robbelroot.de", "+49 999 999")

' Kontakt löschen
repo.DeleteContact(newId)

Transaktionen verwenden

Wenn Du mehrere Zeilen auf einmal einfügen oder aktualisieren musst, packe sie in eine Transaktion. Das ist sowohl schneller als auch sicherer: entweder gelingen alle Operationen oder keine.

Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using transaction = connection.BeginTransaction()
        Using command As New SqliteCommand()
            command.Connection = connection
            command.Transaction = transaction
            command.CommandText = "INSERT INTO Contacts (Name, Email) VALUES (@name, @email)"

            For i As Integer = 1 To 1000
                command.Parameters.Clear()
                command.Parameters.AddWithValue("@name", $"Kontakt {i}")
                command.Parameters.AddWithValue("@email", $"kontakt{i}@example.com")
                command.ExecuteNonQuery()
            Next
        End Using

        transaction.Commit()
    End Using
End Using

Ohne Transaktion kann das Einfügen von 1.000 Zeilen mehrere Sekunden dauern, da SQLite nach jedem einzelnen INSERT committet. Mit Transaktion ist die gleiche Operation in Millisekunden erledigt.

Async/Await: GUI nicht einfrieren

Läuft eine Datenbankabfrage auf dem UI-Thread, friert die gesamte Benutzeroberfläche so lange ein. Mit Async/Await verlagerst Du die Arbeit in den Hintergrund, während die GUI weiter reagiert. Alles zum Thema findest Du im Beitrag zur asynchronen Programmierung in VB.NET.

Public Async Function GetAllContactsAsync() As Task(Of List(Of Dictionary(Of String, Object)))
    Dim contacts As New List(Of Dictionary(Of String, Object))

    Using connection As New SqliteConnection(_connectionString)
        Await connection.OpenAsync()

        Using command As New SqliteCommand("SELECT Id, Name, Email FROM Contacts ORDER BY Name", connection)
            Using reader As SqliteDataReader = Await command.ExecuteReaderAsync()
                While Await reader.ReadAsync()
                    Dim contact As New Dictionary(Of String, Object) From {
                        {"Id", reader.GetInt64(0)},
                        {"Name", reader.GetString(1)},
                        {"Email", If(reader.IsDBNull(2), "", reader.GetString(2))}
                    }
                    contacts.Add(contact)
                End While
            End Using
        End Using
    End Using

    Return contacts
End Function

Das Muster gilt für alle Operationen: OpenAsync() statt Open(), ExecuteNonQueryAsync() statt ExecuteNonQuery(), ReadAsync() statt Read(). Die aufrufende Methode muss dafür als Async Function deklariert sein.

Häufige Stolperfallen und Lösungen

„Database is locked“

Das ist der häufigste SQLite-Fehler. Er tritt auf, wenn mehrere Threads oder Verbindungen gleichzeitig in die Datenbank schreiben wollen. So vermeidest Du ihn:

  • Verbindungen immer freigeben – verwende Using-Blöcke konsequent. Eine vergessene offene Verbindung sperrt die Datei.
  • WAL-Modus aktivieren – Write-Ahead Logging erlaubt gleichzeitiges Lesen und einen schreibenden Zugriff:
Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using walCommand As New SqliteCommand("PRAGMA journal_mode=WAL;", connection)
        walCommand.ExecuteNonQuery()
    End Using
End Using
  • Busy-Timeout setzen – statt sofort zu scheitern, lässt Du SQLite ein paar Sekunden lang erneut versuchen:
Using walCommand As New SqliteCommand("PRAGMA busy_timeout=5000;", connection)
    walCommand.ExecuteNonQuery()
End Using
  • Transaktionen nutzen bei Bulk-Operationen, statt Verbindungen in einer engen Schleife zu öffnen und zu schließen.
  • Lange Lesezugriffe vermeiden während geschrieben wird. Für komplexere Hintergrundarbeit bietet sich asynchrone Programmierung in VB.NET an.

Dateipfad-Probleme

Ein relativer Pfad wie Data Source=myapp.db wird relativ zum aktuellen Arbeitsverzeichnis aufgelöst, das sich je nach Startart unterscheiden kann (Doppelklick vs. Kommandozeile). Verwende einen absoluten Pfad auf Basis von AppContext.BaseDirectory, wie im Application-Path-Artikel gezeigt.

NULL-Behandlung

Prüfe beim Lesen von nullable Spalten immer mit reader.IsDBNull(), bevor Du GetString() oder GetInt64() aufrufst. Sonst bekommst Du zur Laufzeit eine InvalidCastException. Beim Einfügen von NULL-Werten übergibst Du DBNull.Value statt Nothing.

Interessiert?

Du suchst einen erfahrenen .NET-Entwickler?

Ich übernehme Dein Projekt, vom Datenbank-Design bis zur fertigen Anwendung. Schreib mir einfach.

FAQ

Wie erstelle ich eine SQLite-Datenbank in VB.NET?

Öffne einfach eine Verbindung mit einem Dateipfad, der noch nicht existiert: New SqliteConnection("Data Source=myapp.db"). SQLite erstellt die Datei automatisch beim Aufruf von Open().

Wie lautet der SQLite Connection String für VB.NET?

Der minimale Connection String ist Data Source=pfad\zur\datenbank.db. Je nach Bedarf kannst Du Optionen wie Mode=ReadWrite oder Cache=Shared ergänzen.

Warum bekomme ich „database is locked“ in SQLite?

Das passiert, wenn mehrere Verbindungen gleichzeitig schreibend zugreifen oder eine Verbindung nicht sauber geschlossen wurde. Verwende Using-Blöcke, aktiviere den WAL-Modus mit PRAGMA journal_mode=WAL und setze einen Busy-Timeout.

Microsoft.Data.Sqlite oder System.Data.SQLite?

Microsoft.Data.Sqlite ist schlanker, modern und wird von Microsoft gepflegt. System.Data.SQLite ist älter und unterstützt auch .NET Framework 4.0+. Für neue Projekte ab .NET 5+ oder .NET Framework 4.6.1+ ist Microsoft.Data.Sqlite die empfohlene Wahl.

Kann ich SQLite mit Async/Await in VB.NET verwenden?

Ja. Microsoft.Data.Sqlite bietet asynchrone Methoden wie ExecuteNonQueryAsync(), ExecuteReaderAsync() und ExecuteScalarAsync(). Nutze sie mit Await, um die Benutzeroberfläche während der Datenbankoperationen nicht einfrieren zu lassen.

Fazit

SQLite ist der schnellste Weg, eine lokale Datenbank in Deine VB.NET-Anwendung einzubauen. Installiere Microsoft.Data.Sqlite per NuGet, verwende Using-Blöcke für jede Verbindung und schreibe ausschließlich parametrisierte Abfragen. Für Multi-Thread-Szenarien aktiviere den WAL-Modus und setze einen Busy-Timeout, um „database is locked“-Fehler zu vermeiden.

Downloads

VB.NET SQLite Beispielprojekt – WinForms App mit DataGridView und CRUD-Buttons

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.