Uso di SQLite.NET con Android

La libreria SQLite.NET consigliata da Xamarin è un ORM molto semplice che consente di archiviare e recuperare facilmente oggetti nel database SQLite locale in un dispositivo Android. ORM è l'acronimo di Object Relational Mapping( API che consente di salvare e recuperare "oggetti" da un database senza scrivere istruzioni SQL.

Per includere la libreria SQLite.NET in un'app Xamarin, aggiungere il pacchetto NuGet seguente al progetto:

SQLite.NET NuGet package

Sono disponibili diversi pacchetti SQLite. Assicurarsi di scegliere quello corretto (potrebbe non essere il risultato principale nella ricerca).

Importante

SQLite.NET è una libreria di terze parti supportata dal repository praeclarum/sqlite-net.

Dopo aver ottenuto la libreria SQLite.NET disponibile, seguire questa procedura per usarla per accedere a un database:

  1. Aggiungere un'istruzione using: aggiungere l'istruzione seguente ai file C# in cui è necessario l'accesso ai dati:

    using SQLite;
    
  2. Creare un database vuoto: è possibile creare un riferimento al database passando il percorso del file al costruttore della classe SQLite Connessione ion. Non è necessario verificare se il file esiste già. Se necessario, verrà creato automaticamente. In caso contrario, verrà aperto il file di database esistente. La dbPath variabile deve essere determinata in base alle regole descritte in precedenza in questo documento:

    var db = new SQLiteConnection (dbPath);
    
  3. Salva dati: dopo aver creato un oggetto SQLite Connessione ion, i comandi di database vengono eseguiti chiamando i relativi metodi, ad esempio CreateTable e Insert nel modo seguente:

    db.CreateTable<Stock> ();
    db.Insert (newStock); // after creating the newStock object
    
  4. Recupera dati : per recuperare un oggetto (o un elenco di oggetti) utilizzare la sintassi seguente:

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

Esempio di accesso ai dati di base

Il codice di esempio DataAccess_Basic per questo documento è simile al seguente durante l'esecuzione in Android. Il codice illustra come eseguire semplici operazioni di SQLite.NET e mostra i risultati come testo nella finestra principale dell'applicazione.

Android

Android SQLite.NET sample

L'esempio di codice seguente illustra un'intera interazione del database usando la libreria SQLite.NET per incapsulare l'accesso al database sottostante. Mostra:

  1. Creazione del file di database

  2. Inserimento di alcuni dati creando oggetti e quindi salvandoli

  3. Eseguire query sui dati

È necessario includere questi spazi dei nomi:

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

L'ultimo richiede l'aggiunta di SQLite al progetto. Si noti che la tabella di database SQLite viene definita aggiungendo attributi a una classe (la Stock classe) anziché a un comando CREATE TABLE.

[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);
    }
}

Se si usa l'attributo [Table] senza specificare un parametro nome tabella, la tabella di database sottostante avrà lo stesso nome della classe (in questo caso "Stock"). Il nome effettivo della tabella è importante se si scrivono query SQL direttamente sul database anziché usare i metodi di accesso ai dati ORM. Analogamente, l'attributo [Column("_id")] è facoltativo e, se assente, verrà aggiunta una colonna alla tabella con lo stesso nome della proprietà nella classe .

Attributi SQLite

Gli attributi comuni che è possibile applicare alle classi per controllare la modalità di archiviazione nel database sottostante includono:

  • [PrimaryKey] : questo attributo può essere applicato a una proprietà integer per forzarlo come chiave primaria della tabella sottostante. Le chiavi primarie composite non sono supportate.

  • [AutoIncrement] : questo attributo causerà l'incremento automatico del valore di una proprietà integer per ogni nuovo oggetto inserito nel database

  • [Column(name)] : il name parametro imposta il nome della colonna di database sottostante.

  • [Table(name)] : contrassegna la classe come in grado di essere archiviata in una tabella SQLite sottostante con il nome specificato.

  • [MaxLength(value)] : limitare la lunghezza di una proprietà di testo quando si tenta di inserire un database. L'utilizzo del codice deve convalidarlo prima di inserire l'oggetto perché questo attributo è "controllato" solo quando viene tentata un'operazione di inserimento o aggiornamento del database.

  • [Ignora] : fa sì che SQLite.NET ignori questa proprietà. Ciò è particolarmente utile per le proprietà con un tipo che non può essere archiviato nel database o proprietà che non possono essere risolte automaticamente da SQLite.

  • [Univoco] : garantisce che i valori nella colonna del database sottostante siano univoci.

La maggior parte di questi attributi è facoltativa. È consigliabile specificare sempre una chiave primaria integer in modo che le query di selezione ed eliminazione possano essere eseguite in modo efficiente sui dati.

Query più complesse

Per eseguire altre operazioni sui dati, è possibile usare i metodi SQLiteConnection seguenti:

  • Insert : aggiunge un nuovo oggetto al database.

  • Get<T> : tenta di recuperare un oggetto usando la chiave primaria.

  • Table<T> : restituisce tutti gli oggetti della tabella.

  • Delete : elimina un oggetto usando la relativa chiave primaria.

  • Query<T> : eseguire una query SQL che restituisce un numero di righe (come oggetti).

  • Execute: usare questo metodo (e non Query) quando non si prevede che le righe vengano restituite da SQL(ad esempio IN edizione Standard RT, UPDATE e DELETE).

Recupero di un oggetto tramite la chiave primaria

SQLite.Net fornisce il metodo Get per recuperare un singolo oggetto in base alla relativa chiave primaria.

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

Selezione di un oggetto tramite Linq

I metodi che restituiscono raccolte supportano IEnumerable<T> in modo da poter usare Linq per eseguire query o ordinare il contenuto di una tabella. Il codice seguente mostra un esempio che usa Linq per filtrare tutte le voci che iniziano con la lettera "A":

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

Selezione di un oggetto tramite SQL

Anche se SQLite.Net può fornire l'accesso basato su oggetti ai dati, a volte potrebbe essere necessario eseguire una query più complessa rispetto a Linq consente (o potrebbe essere necessario ottenere prestazioni più veloci). È possibile usare i comandi SQL con il metodo Query, come illustrato di seguito:

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

Nota

Quando si scrivono istruzioni SQL direttamente, si crea una dipendenza dai nomi di tabelle e colonne nel database, generati dalle classi e dai relativi attributi. Se si modificano tali nomi nel codice, è necessario ricordare di aggiornare eventuali istruzioni SQL scritte manualmente.

Eliminazione di un oggetto

La chiave primaria viene usata per eliminare la riga, come illustrato di seguito:

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

È possibile verificare il rowcount numero di righe interessate (eliminate in questo caso).

Uso di SQLite.NET con più thread

SQLite supporta tre diverse modalità di threading: a thread singolo, multithread e serializzato. Se si vuole accedere al database da più thread senza restrizioni, è possibile configurare SQLite in modo da usare la modalità di threading serializzato . È importante impostare questa modalità all'inizio dell'applicazione, ad esempio all'inizio del OnCreate metodo .

Per modificare la modalità di threading, chiamare SqliteConnection.SetConfig. Ad esempio, questa riga di codice configura SQLite per la modalità serializzata :

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

La versione Android di SQLite presenta una limitazione che richiede alcuni passaggi aggiuntivi. Se la chiamata a SqliteConnection.SetConfig genera un'eccezione SQLite, library used incorrectlyad esempio , è necessario usare la soluzione alternativa seguente:

  1. Collegamento alla libreria di libsqlite.so nativa in modo che le sqlite3_shutdown API e sqlite3_initialize siano rese disponibili all'app:

    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_shutdown();
    
    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_initialize();
    
  2. All'inizio del OnCreate metodo aggiungere questo codice per arrestare SQLite, configurarlo per la modalità serializzata e reinizializzare SQLite:

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

Questa soluzione alternativa funziona anche per la Mono.Data.Sqlite libreria. Per altre informazioni su SQLite e multithreading, vedere SQLite e Più thread.