Verwenden von SQLite.NET mit Android

Die SQLite.NET Bibliothek, die Xamarin empfiehlt, ist ein sehr einfaches ORM, mit dem Sie Problemlos Objekte in der lokalen SQLite-Datenbank auf einem Android-Gerät speichern und abrufen können. ORM steht für Object Relational Mapping – eine API, mit der Sie "Objekte" aus einer Datenbank speichern und abrufen können, ohne SQL-Anweisungen schreiben zu müssen.

Um die SQLite.NET-Bibliothek in eine Xamarin-App einzuschließen, fügen Sie ihrem Projekt das folgende NuGet-Paket hinzu:

SQLite.NET NuGet-Paket

Es gibt eine Reihe verschiedener SQLite-Pakete– achten Sie darauf, das richtige paket auszuwählen (dies ist möglicherweise nicht das beste Ergebnis in der Suche).

Wichtig

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

Sobald Sie die SQLite.NET Bibliothek verfügbar haben, führen Sie die folgenden drei Schritte aus, um sie für den Zugriff auf eine Datenbank zu verwenden:

  1. Hinzufügen einer using-Anweisung : Fügen Sie die folgende Anweisung zu den C#-Dateien hinzu, in denen Datenzugriff erforderlich ist:

    using SQLite;
    
  2. Erstellen einer leeren Datenbank : Ein Datenbankverweis kann erstellt werden, indem der Dateipfad des SQLiteConnection-Klassenkonstruktors übergeben wird. Sie müssen nicht überprüfen, ob die Datei bereits vorhanden ist. Sie wird bei Bedarf automatisch erstellt, andernfalls wird die vorhandene Datenbankdatei geöffnet. Die dbPath Variable sollte gemäß den weiter oben in diesem Dokument erläuterten Regeln bestimmt werden:

    var db = new SQLiteConnection (dbPath);
    
  3. Daten speichern : Nachdem Sie ein SQLiteConnection-Objekt erstellt haben, werden Datenbankbefehle ausgeführt, indem die zugehörigen Methoden wie CreateTable und Insert wie folgt aufgerufen werden:

    db.CreateTable<Stock> ();
    db.Insert (newStock); // after creating the newStock object
    
  4. Abrufen von Daten : Verwenden Sie die folgende Syntax, um ein Objekt (oder eine Liste von Objekten) abzurufen:

    var stock = db.Get<Stock>(5); // primary key id of 5
    var stockList = db.Table<Stock>();
    

Beispiel für den einfachen Datenzugriff

Der DataAccess_Basic Beispielcode für dieses Dokument sieht bei Der Ausführung unter Android wie folgt aus. Der Code veranschaulicht, wie einfache SQLite.NET-Vorgänge ausgeführt werden, und zeigt die Ergebnisse als Text im Standard-Fenster der Anwendung an.

Android

Beispiel für Android SQLite.NET

Das folgende Codebeispiel zeigt eine gesamte Datenbankinteraktion mithilfe der SQLite.NET-Bibliothek, um den zugrunde liegenden Datenbankzugriff zu kapseln. Es zeigt Folgendes an:

  1. Erstellen der Datenbankdatei

  2. Einfügen einiger Daten durch Erstellen von Objekten und anschließendes Speichern

  3. Abfragen der Daten

Sie müssen die folgenden Namespaces einschließen:

using SQLite; // from the github SQLite.cs class

Die letzte erfordert, dass Sie SQLite zu Ihrem Projekt hinzugefügt haben. Beachten Sie, dass die SQLite-Datenbanktabelle durch Hinzufügen von Attributen zu einer Klasse (der Stock -Klasse) und nicht durch einen CREATE TABLE-Befehl definiert wird.

[Table("Items")]
public class Stock {
    [PrimaryKey, AutoIncrement, Column("_id")]
    public int Id { get; set; }
    [MaxLength(8)]
    public string Symbol { get; set; }
}
public static void DoSomeDataAccess () {
       Console.WriteLine ("Creating database, if it doesn't already exist");
   string dbPath = Path.Combine (
        Environment.GetFolderPath (Environment.SpecialFolder.Personal),
        "ormdemo.db3");
   var db = new SQLiteConnection (dbPath);
   db.CreateTable<Stock> ();
   if (db.Table<Stock> ().Count() == 0) {
        // only insert the data if it doesn't already exist
        var newStock = new Stock ();
        newStock.Symbol = "AAPL";
        db.Insert (newStock);
        newStock = new Stock ();
        newStock.Symbol = "GOOG";
        db.Insert (newStock);
        newStock = new Stock ();
        newStock.Symbol = "MSFT";
        db.Insert (newStock);
    }
    Console.WriteLine("Reading data");
    var table = db.Table<Stock> ();
    foreach (var s in table) {
        Console.WriteLine (s.Id + " " + s.Symbol);
    }
}

Die Verwendung des [Table] Attributs ohne Angabe eines Tabellennamenparameters führt dazu, dass die zugrunde liegende Datenbanktabelle den gleichen Namen wie die -Klasse hat (in diesem Fall "Stock"). Der tatsächliche Tabellenname ist wichtig, wenn Sie SQL-Abfragen direkt für die Datenbank schreiben, anstatt die ORM-Datenzugriffsmethoden zu verwenden. Ebenso ist das [Column("_id")] Attribut optional, und wenn keine Spalte vorhanden ist, wird der Tabelle mit demselben Namen wie die -Eigenschaft in der -Klasse hinzugefügt.

SQLite-Attribute

Zu den allgemeinen Attributen, die Sie auf Ihre Klassen anwenden können, um zu steuern, wie sie in der zugrunde liegenden Datenbank gespeichert werden, gehören:

  • [PrimaryKey] – Dieses Attribut kann auf eine ganzzahlige Eigenschaft angewendet werden, um zu erzwingen, dass sie der Primärschlüssel der zugrunde liegenden Tabelle ist. Zusammengesetzte Primärschlüssel werden nicht unterstützt.

  • [AutoIncrement] – Dieses Attribut bewirkt, dass der Wert einer ganzzahligen Eigenschaft für jedes neue Objekt, das in die Datenbank eingefügt wird, automatisch erhöht wird.

  • [Column(name)] – Der name Parameter legt den Namen der zugrunde liegenden Datenbankspalte fest.

  • [Table(name)] – Markiert die Klasse als in einer zugrunde liegenden SQLite-Tabelle mit dem angegebenen Namen gespeichert werden kann.

  • [MaxLength(value)] – Schränken Sie die Länge einer Texteigenschaft ein, wenn versucht wird, eine Datenbankeinfügung einzufügen. Wenn Code verwendet wird, sollte dies vor dem Einfügen des Objekts überprüft werden, da dieses Attribut nur beim Versuch eines Datenbankeinfügungs- oder Aktualisierungsvorgangs "überprüft" wird.

  • [Ignore] – Bewirkt, dass SQLite.NET diese Eigenschaft ignoriert. Dies ist besonders nützlich für Eigenschaften, die über einen Typ verfügen, der nicht in der Datenbank gespeichert werden kann, oder für Eigenschaften, die Auflistungen modellieren, die nicht automatisch von SQLite aufgelöst werden können.

  • [Eindeutig] – Stellt sicher, dass die Werte in der zugrunde liegenden Datenbankspalte eindeutig sind.

Die meisten dieser Attribute sind optional. Sie sollten immer einen ganzzahligen Primärschlüssel angeben, damit Auswahl- und Löschabfragen effizient für Ihre Daten ausgeführt werden können.

Komplexere Abfragen

Die folgenden Methoden für SQLiteConnection können verwendet werden, um andere Datenvorgänge auszuführen:

  • Einfügen : Fügt der Datenbank ein neues Objekt hinzu.

  • Erhalten<T> – Versucht, ein Objekt mithilfe des Primärschlüssels abzurufen.

  • Tabelle<T> : Gibt alle Objekte in der Tabelle zurück.

  • Löschen : Löscht ein Objekt mithilfe seines Primärschlüssels.

  • Abfrage<T> – Ausführen einer SQL-Abfrage, die eine Anzahl von Zeilen (als Objekte) zurückgibt.

  • Execute : Verwenden Sie diese Methode (und nicht Query), wenn Sie keine Zeilen zurück von sql erwarten (z. B. INSERT-, UPDATE- und DELETE-Anweisungen).

Abrufen eines Objekts durch den Primärschlüssel

SQLite.Net stellt die Get-Methode bereit, um ein einzelnes Objekt basierend auf seinem Primärschlüssel abzurufen.

var existingItem = db.Get<Stock>(3);

Auswählen eines Objekts mithilfe von Linq

Methoden, die Sammlungen zurückgeben, unterstützen IEnumerable<T> , sodass Sie Linq verwenden können, um den Inhalt einer Tabelle abzufragen oder zu sortieren. Der folgende Code zeigt ein Beispiel, in dem Linq verwendet wird, um alle Einträge herauszufiltern, die mit dem Buchstaben "A" beginnen:

var apple = from s in db.Table<Stock>()
    where s.Symbol.StartsWith ("A")
    select s;
Console.WriteLine ("-> " + apple.FirstOrDefault ().Symbol);

Auswählen eines Objekts mithilfe von SQL

Obwohl SQLite.Net objektbasierten Zugriff auf Ihre Daten ermöglichen können, müssen Sie manchmal eine komplexere Abfrage durchführen, als Linq zulässt (oder Sie benötigen möglicherweise eine schnellere Leistung). Sie können SQL-Befehle mit der Query-Methode verwenden, wie hier gezeigt:

var stocksStartingWithA = db.Query<Stock>("SELECT * FROM Items WHERE Symbol = ?", "A");
foreach (var s in stocksStartingWithA) {
    Console.WriteLine ("a " + s.Symbol);
}

Hinweis

Wenn Sie SQL-Anweisungen direkt schreiben, erstellen Sie eine Abhängigkeit von den Namen von Tabellen und Spalten in Ihrer Datenbank, die aus Ihren Klassen und deren Attributen generiert wurden. Wenn Sie diese Namen in Ihrem Code ändern, müssen Sie daran denken, alle manuell geschriebenen SQL-Anweisungen zu aktualisieren.

Löschen eines Objekts

Der Primärschlüssel wird verwendet, um die Zeile zu löschen, wie hier gezeigt:

var rowcount = db.Delete<Stock>(someStock.Id); // Id is the primary key

Sie können überprüfen rowcount , um zu bestätigen, wie viele Zeilen betroffen waren (in diesem Fall gelöscht).

Verwenden von SQLite.NET mit mehreren Threads

SQLite unterstützt drei verschiedene Threadingmodi: Einzelthread, Multithread und Serialisiert. Wenn Sie über mehrere Threads ohne Einschränkungen auf die Datenbank zugreifen möchten, können Sie SQLite für die Verwendung des serialisierten Threadingmodus konfigurieren. Es ist wichtig, diesen Modus frühzeitig in Ihrer Anwendung festzulegen (z. B. am Anfang der OnCreate -Methode).

Um den Threadingmodus zu ändern, rufen Sie auf SqliteConnection.SetConfig. In dieser Codezeile wird beispielsweise SQLite für den serialisierten Modus konfiguriert:

using using Mono.Data.Sqlite;
...
SqliteConnection.SetConfig(SQLiteConfig.Serialized);

Die Android-Version von SQLite verfügt über eine Einschränkung, die einige weitere Schritte erfordert. Wenn der Aufruf von SqliteConnection.SetConfig eine SQLite-Ausnahme wie library used incorrectlyerzeugt, müssen Sie die folgende Problemumgehung verwenden:

  1. Verknüpfen Sie die native libsqlite.so Bibliothek, damit die sqlite3_shutdown APIs und sqlite3_initialize für die App verfügbar gemacht werden:

    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_shutdown();
    
    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_initialize();
    
  2. Fügen Sie am Anfang der OnCreate Methode diesen Code hinzu, um SQLite herunterzufahren, für den serialisierten Modus zu konfigurieren und SQLite erneut zu initialisieren:

    using using Mono.Data.Sqlite;
    ...
    sqlite3_shutdown();
    SqliteConnection.SetConfig(SQLiteConfig.Serialized);
    sqlite3_initialize();
    

Diese Problemumgehung funktioniert auch für die Mono.Data.Sqlite Bibliothek. Weitere Informationen zu SQLite und Multithreading finden Sie unter SQLite und Mehrere Threads.