Freigeben über


Lokale .NET MAUI-Datenbanken

Beispiel durchsuchen.Durchsuchen Sie das Beispiel

Das SQLite-Datenbankmodul ermöglicht .NET Multi-Platform App UI (.NET MAUI)-Apps, Datenobjekte in freigegebenem Code zu laden und speichern. Sie können SQLite.NET in .NET MAUI-Apps integrieren, um Informationen in einer lokalen Datenbank zu speichern und abzurufen, indem Sie die folgenden Schritte ausführen:

  1. Installieren Sie das NuGet-Paket.
  2. Konfigurieren Sie Konstanten.
  3. Erstellen Sie eine Datenbankzugriffsklasse.
  4. Zugangsdaten.
  5. Erweiterte Konfiguration

In diesem Artikel wird das NuGet-Paket sqlite-net-pcl verwendet, um SQLite-Datenbankzugriff auf eine Tabelle zum Speichern von TODO-Elementen bereitzustellen. Eine Alternative besteht darin, das NuGet-Paket Microsoft.Data.Sqlite zu verwenden, das ein einfacher ADO.NET-Anbieter für SQLite ist. Microsoft.Data.Sqlite implementiert die allgemeinen ADO.NET-Abstraktionen für Funktionen wie Verbindungen, Befehle und Datenleser.

Installieren Sie das SQLite NuGet-Paket

Verwenden Sie den NuGet-Paket-Manager, um nach dem sqlite-net-pcl-Paket zu suchen und die neueste Version zu Ihrem .NET MAUI-App-Projekt hinzuzufügen.

Es gibt eine Reihe von NuGet-Paketen mit ähnlichen Namen. Das richtige Paket verfügt über die folgenden Attribute:

  • ID: sqlite-net-pcl
  • Ersteller: SQLite-net
  • Besitzer: praeclarum
  • NuGet-Link: sqlite-net-pcl

Verwenden Sie trotz des Paketnamens das sqlite-net-pcl NuGet-Paket in .NET MAUI-Projekten.

Wichtig

SQLite.NET ist eine Drittanbieterbibliothek, die vom praeclarum/sqlite-net-Repository unterstützt wird.

SQLitePCLRaw.bundle_green installieren

Zusätzlich zu sqlite-net-pcl müssen Sie temporär die zugrundeliegende Abhängigkeit installieren, die SQLite auf jeder Plattform verfügbar macht:

  • ID: SQLitePCLRaw.bundle_green
  • Version:>= 2.1.0
  • Autoren: Eric Sink
  • Eigentümer: Eric Sink
  • NuGet-Link: SQLitePCLRaw.bundle_green

Konfigurieren von App-Konstanten

Konfigurationsdaten, wie etwa der Datenbank-Dateiname und -Pfad, können als Konstanten in Ihrer App gespeichert werden. Das Beispielprojekt enthält die Datei Constants.cs, die allgemeine Konfigurationsdaten bereitstellt:

public static class Constants
{
    public const string DatabaseFilename = "TodoSQLite.db3";

    public const SQLite.SQLiteOpenFlags Flags =
        // open the database in read/write mode
        SQLite.SQLiteOpenFlags.ReadWrite |
        // create the database if it doesn't exist
        SQLite.SQLiteOpenFlags.Create |
        // enable multi-threaded database access
        SQLite.SQLiteOpenFlags.SharedCache;

    public static string DatabasePath =>
        Path.Combine(FileSystem.AppDataDirectory, DatabaseFilename);
}

In diesem Beispiel gibt die Konstantendatei Standard-SQLiteOpenFlagEnumerationswerte an, die zum Initialisieren der Datenbankverbindung verwendet werden. Die SQLiteOpenFlag-Enumeration unterstützt diese Werte:

  • Create: Die Verbindung erstellt die Datenbankdatei automatisch, wenn sie nicht vorhanden ist.
  • FullMutex: Die Verbindung wird im serialisierten Threadingmodus geöffnet.
  • NoMutex: Die Verbindung wird im Multithreadingmodus geöffnet.
  • PrivateCache: Die Verbindung nimmt nicht am freigegebenen Cache teil, auch wenn sie aktiviert ist.
  • ReadWrite: Die Verbindung kann Daten lesen und schreiben.
  • SharedCache: Die Verbindung nimmt am freigegebenen Cache teil, wenn sie aktiviert ist.
  • ProtectionComplete: Die Datei ist verschlüsselt und nicht zugänglich, während das Gerät gesperrt ist.
  • ProtectionCompleteUnlessOpen: Die Datei wird verschlüsselt, bis sie geöffnet wird, ist aber nach wie vor zugänglich, wenn die oder der Benutzende das Gerät sperrt.
  • ProtectionCompleteUntilFirstUserAuthentication: Die Datei wird verschlüsselt, bis die oder der Benutzende das Gerät gestartet und entsperrt hat.
  • ProtectionNone: Die Datenbankdatei ist nicht verschlüsselt.

Je nachdem, wie die Datenbank verwendet wird, müssen Sie möglicherweise unterschiedliche Flags angeben. Weitere Informationen SQLiteOpenFlagsfinden Sie unter Neue Datenbankverbindung öffnen auf sqlite.org.

Datenbankzugriffsklasse erstellen

Eine Datenbankwrapperklasse abstrahiert die Datenzugriffsebene von der restlichen App. Diese Klasse zentralisiert die Abfragelogik und vereinfacht die Verwaltung der Datenbankinitialisierung, sodass es einfacher ist, Datenoperationen zu refaktorisieren oder zu erweitern, wenn die App wächst. Die Beispiel-App definiert dazu eine TodoItemDatabase-Klasse.

Verzögerte Initialisierung

Die TodoItemDatabase verwendet die asynchrone verzögerte Initialisierung, um die Initialisierung der Datenbank bis zum ersten Zugriff zu verzögern. Dazu wird eine einfache Init-Methode verwendet, die von jeder Methode der Klasse aufgerufen wird:

public class TodoItemDatabase
{
    SQLiteAsyncConnection Database;

    public TodoItemDatabase()
    {
    }

    async Task Init()
    {
        if (Database is not null)
            return;

        Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
        var result = await Database.CreateTableAsync<TodoItem>();
    }
    ...
}

Methoden zur Datenmanipulation

Die Klasse TodoItemDatabase enthält Methoden für die vier Arten der Datenmanipulation: Erstellen, Lesen, Bearbeiten und Löschen. Die SQLite.NET-Bibliothek bietet eine einfache Object Relational Map (ORM), mit der das Speichern und Abrufen von Objekten ohne das Schreiben von SQL-Anweisungen möglich ist.

Das folgende Beispiel zeigt die Methoden zur Datenmanipulation in der Beispiel-App:

public class TodoItemDatabase
{
    ...
    public async Task<List<TodoItem>> GetItemsAsync()
    {
        await Init();
        return await Database.Table<TodoItem>().ToListAsync();
    }

    public async Task<List<TodoItem>> GetItemsNotDoneAsync()
    {
        await Init();
        return await Database.Table<TodoItem>().Where(t => t.Done).ToListAsync();

        // SQL queries are also possible
        //return await Database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
    }

    public async Task<TodoItem> GetItemAsync(int id)
    {
        await Init();
        return await Database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
    }

    public async Task<int> SaveItemAsync(TodoItem item)
    {
        await Init();
        if (item.ID != 0)
            return await Database.UpdateAsync(item);
        else
            return await Database.InsertAsync(item);
    }

    public async Task<int> DeleteItemAsync(TodoItem item)
    {
        await Init();
        return await Database.DeleteAsync(item);
    }
}

Zugreifen auf Daten

Die Klasse TodoItemDatabase kann als Singleton registriert werden, das in der gesamten App verwendet werden kann, wenn Sie mit Abhängigkeitsinjektion arbeiten. Beispielsweise können Sie Ihre Seiten und die Zugriffsklasse für die Datenbank als Dienste für das IServiceCollection-Objekt in MauiProgram.cs mit den Methoden AddSingleton und AddTransient registrieren:

builder.Services.AddSingleton<TodoListPage>();
builder.Services.AddTransient<TodoItemPage>();

builder.Services.AddSingleton<TodoItemDatabase>();

Diese Dienste können dann automatisch in Klassenkonstruktoren eingefügt und aufgerufen werden:

TodoItemDatabase database;

public TodoItemPage(TodoItemDatabase todoItemDatabase)
{
    InitializeComponent();
    database = todoItemDatabase;
}

async void OnSaveClicked(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(Item.Name))
    {
        await DisplayAlert("Name Required", "Please enter a name for the todo item.", "OK");
        return;
    }

    await database.SaveItemAsync(Item);
    await Shell.Current.GoToAsync("..");
}

Alternativ können auch neue Instanzen der Zugriffsklasse für die Datenbank erstellt werden:

TodoItemDatabase database;

public TodoItemPage()
{
    InitializeComponent();
    database = new TodoItemDatabase();
}

Weitere Informationen zur Abhängigkeitsinjektion in .NET MAUI-Apps finden Sie unter Abhängigkeitsinjektion.

Erweiterte Konfiguration

SQLite bietet eine robuste API mit mehr Funktionen als in diesem Artikel und der Beispiel-App behandelt werden. Die folgenden Abschnitte behandeln Funktionen, die für die Skalierbarkeit wichtig sind.

Weitere Informationen finden Sie in der SQLite- Dokumentation unter sqlite.org.

Write-Ahead-Protokollierung

Standardmäßig verwendet SQLite ein herkömmliches Rollbackjournal. Eine Kopie des unveränderten Datenbankinhalts wird in eine separate Rollbackdatei geschrieben, dann werden die Änderungen direkt in die Datenbankdatei geschrieben. Das COMMIT erfolgt, wenn das Rollbackjournal gelöscht wird.

Write-Ahead-Protokollierung (WAL) schreibt Änderungen zunächst in eine separate WAL-Datei. Im WAL-Modus ist ein COMMIT ein spezieller Datensatz, der an die WAL-Datei angehängt wird und der es ermöglicht, mehrere Transaktionen in einer einzigen WAL-Datei durchzuführen. Eine WAL-Datei wird in einem speziellen Vorgang, dem Prüfpunkt, wieder mit der Datenbankdatei zusammengeführt.

WAL kann für lokale Datenbanken schneller sein, da sich Lesende und Schreibende nicht gegenseitig blockieren, sodass Lese- und Schreibvorgänge gleichzeitig ausgeführt werden können. Der WAL-Modus erlaubt jedoch keine Änderung der Seitengröße, fügt der Datenbank zusätzliche Dateiverknüpfungen hinzu und bietet einen zusätzlichen Prüfpunkt-Vorgang.

Um WAL in SQLite.NET zu aktivieren, rufen Sie die EnableWriteAheadLoggingAsync-Methode für die SQLiteAsyncConnection-Instanz auf:

await Database.EnableWriteAheadLoggingAsync();

Weitere Informationen finden Sie in SQLite- Write-Ahead-Protokollierung unter sqlite.org..

Kopieren einer Datenbank

Es gibt mehrere Fälle, in denen es notwendig sein kann, eine SQLite-Datenbank zu kopieren:

  • Eine Datenbank wurde mit Ihrer Anwendung geliefert, muss aber in einen beschreibbaren Speicher auf dem mobilen Gerät kopiert oder verschoben werden.
  • Sie benötigen eine Sicherung oder Kopie der Datenbank.
  • Sie müssen die Datenbankdatei versionieren, verschieben oder umbenennen.

Im Allgemeinen ist das Verschieben, Umbenennen oder Kopieren einer Datenbankdatei der gleiche Vorgang wie bei jedem anderen Dateityp, mit einigen zusätzlichen Aspekten:

  • Vor dem Verschieben der Datenbankdatei sollten alle Datenbankverbindungen geschlossen werden.
  • Wenn Sie Write-Ahead-Protokollierung verwenden, erstellt SQLite eine Shared Memory Access (.shm)-Datei und eine (Write Ahead Log) (.wal)-Datei. Stellen Sie sicher, dass Sie alle Änderungen auch auf diese Dateien anwenden.