Sdílet prostřednictvím


Xamarin.Forms Místní databáze

Databázový stroj SQLite umožňuje Xamarin.Forms aplikacím načítat a ukládat datové objekty ve sdíleném kódu. Ukázková aplikace používá k ukládání položek úkolů tabulku databáze SQLite. Tento článek popisuje, jak používat SQLite.Net ve sdíleném kódu k ukládání a načítání informací v místní databázi.

Snímky obrazovky s aplikací Todolist v iOSu a Androidu

Integrujte SQLite.NET do mobilních aplikací pomocí následujícího postupu:

  1. Nainstalujte balíček NuGet.
  2. Konfigurujte konstanty.
  3. Vytvořte třídu přístupu k databázi.
  4. Přístup k datům v Xamarin.Forms.
  5. Pokročilá konfigurace.

Instalace balíčku NuGet SQLite

Pomocí správce balíčků NuGet vyhledejte sqlite-net-pcl a přidejte nejnovější verzi do projektu sdíleného kódu.

Existuje několik balíčků NuGet s podobnými názvy. Správný balíček má tyto atributy:

  • ID: sqlite-net-pcl
  • Autoři: SQLite-net
  • Vlastníci: praeclarum
  • Odkaz na NuGet: sqlite-net-pcl

I přes název balíčku použijte balíček NuGet sqlite-net-pcl i v projektech .NET Standard.

Důležité

SQLite.NET je knihovna třetí strany podporovaná z úložiště praeclarum/sqlite-net.

Konfigurace konstant aplikací

Ukázkový projekt obsahuje soubor Constants.cs , který poskytuje běžná konfigurační data:

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
    {
        get
        {
            var basePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            return Path.Combine(basePath, DatabaseFilename);
        }
    }
}

Soubor konstant určuje výchozí SQLiteOpenFlag hodnoty výčtu, které se používají k inicializaci připojení k databázi. Výčet SQLiteOpenFlag podporuje tyto hodnoty:

  • Create: Připojení automaticky vytvoří soubor databáze, pokud neexistuje.
  • FullMutex: Připojení se otevře v režimu serializovaného podprocesu.
  • NoMutex: Připojení se otevře v režimu více vláken.
  • PrivateCache: Připojení se nebude účastnit sdílené mezipaměti, i když je povolené.
  • ReadWrite: Připojení může číst a zapisovat data.
  • SharedCache: Připojení se bude účastnit sdílené mezipaměti, pokud je povolená.
  • ProtectionComplete: Soubor je zašifrovaný a nepřístupný, když je zařízení zamknuté.
  • ProtectionCompleteUnlessOpen: Soubor se zašifruje, dokud se neotevře, ale bude přístupný i v případě, že uživatel zařízení zamkne.
  • ProtectionCompleteUntilFirstUserAuthentication: Soubor se zašifruje, dokud uživatel zařízení nespustí a odemkne.
  • ProtectionNone: Soubor databáze není zašifrovaný.

V závislosti na způsobu použití databáze možná budete muset zadat různé příznaky. Další informace najdete v SQLiteOpenFlagstématu Otevření nového připojení k databázi na sqlite.org.

Vytvoření třídy přístupu k databázi

Třída obálky databáze abstrahuje vrstvu přístupu k datům ze zbytku aplikace. Tato třída centralizuje logiku dotazů a zjednodušuje správu inicializace databáze, což usnadňuje refaktoring nebo rozšíření operací s daty při růstu aplikace. Aplikace Todo definuje TodoItemDatabase třídu pro tento účel.

Opožděná inicializace

Používá TodoItemDatabase asynchronní opožděnou inicializaci reprezentovanou vlastní AsyncLazy<T> třídou ke zpoždění inicializace databáze, dokud nebude poprvé přístupná:

public class TodoItemDatabase
{
    static SQLiteAsyncConnection Database;

    public static readonly AsyncLazy<TodoItemDatabase> Instance = new AsyncLazy<TodoItemDatabase>(async () =>
    {
        var instance = new TodoItemDatabase();
        CreateTableResult result = await Database.CreateTableAsync<TodoItem>();
        return instance;
    });

    public TodoItemDatabase()
    {
        Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
    }

    //...
}

Pole Instance slouží k vytvoření databázové tabulky pro TodoItem objekt, pokud ještě neexistuje, a vrátí jako jednoúčelový TodoItemDatabase . Pole Instance typu AsyncLazy<TodoItemDatabase> se sestaví při prvním čekání. Pokud se více vláken pokusí o přístup k poli současně, budou všechny používat jedinou konstrukci. Po dokončení stavby jsou všechny await operace dokončeny. Kromě toho všechny await operace po dokončení stavby budou pokračovat okamžitě, protože hodnota je k dispozici.

Poznámka:

Připojení k databázi je statické pole, které zajišťuje, aby se jednoúčelové připojení databáze používalo po dobu životnosti aplikace. Použití trvalého statického připojení nabízí lepší výkon než otevírání a zavírání připojení vícekrát během jedné relace aplikace.

Asynchronní opožděná inicializace

Aby bylo možné spustit inicializaci databáze, vyhnout se blokování provádění a mít možnost zachytit výjimky, ukázková aplikace používá asynchronní opožděné initalizace reprezentované AsyncLazy<T> třídou:

public class AsyncLazy<T>
{
    readonly Lazy<Task<T>> instance;

    public AsyncLazy(Func<T> factory)
    {
        instance = new Lazy<Task<T>>(() => Task.Run(factory));
    }

    public AsyncLazy(Func<Task<T>> factory)
    {
        instance = new Lazy<Task<T>>(() => Task.Run(factory));
    }

    public TaskAwaiter<T> GetAwaiter()
    {
        return instance.Value.GetAwaiter();
    }
}

Třída AsyncLazy kombinuje Lazy<T> a Task<T> typy k vytvoření opožděné inicializované úlohy, která představuje inicializaci prostředku. Delegát továrny předaný konstruktoru může být synchronní nebo asynchronní. Delegáti továrny budou spuštěni ve vlákně fondu vláken a nebudou spuštěni více než jednou (i když se je více vláken pokusí spustit současně). Po dokončení delegáta továrny je k dispozici opožděná inicializovaná hodnota a všechny metody čekající na AsyncLazy<T> instanci obdrží hodnotu. Další informace naleznete v tématu AsyncLazy.

Metody manipulace s daty

Třída TodoItemDatabase obsahuje metody pro čtyři typy manipulace s daty: vytvoření, čtení, úpravy a odstranění. Knihovna SQLite.NET poskytuje jednoduchou relační mapu objektů (ORM), která umožňuje ukládat a načítat objekty bez psaní příkazů SQL.

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

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

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

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

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

Přístup k datům v Xamarin.Forms

Třída TodoItemDatabase zveřejňuje Instance pole, prostřednictvím kterého lze vyvolat operace přístupu k datům ve TodoItemDatabase třídě:

async void OnSaveClicked(object sender, EventArgs e)
{
    var todoItem = (TodoItem)BindingContext;
    TodoItemDatabase database = await TodoItemDatabase.Instance;
    await database.SaveItemAsync(todoItem);

    // Navigate backwards
    await Navigation.PopAsync();
}

Rozšířená konfigurace

SQLite poskytuje robustní rozhraní API s více funkcemi, než je popsáno v tomto článku a ukázkové aplikaci. Následující části se týkají funkcí, které jsou důležité pro škálovatelnost.

Další informace najdete v dokumentaci KQLite na sqlite.org.

Protokolování před zápisem

Ve výchozím nastavení používá SQLite tradiční deník vrácení zpět. Kopie nezměněného obsahu databáze se zapíše do samostatného souboru vrácení zpět a změny se zapíšou přímo do souboru databáze. Potvrzení nastane při odstranění deníku vrácení zpět.

Protokolování před zápisem (WAL) zapisuje změny do samostatného souboru WAL. V režimu WAL je commit speciální záznam, připojený k souboru WAL, který umožňuje více transakcí nastat v jednom souboru WAL. Soubor WAL se sloučí zpět do databázového souboru ve speciální operaci označované jako kontrolní bod.

Wal může být rychlejší pro místní databáze, protože čtenáři a zapisovače navzájem neblokují, což umožňuje souběžné operace čtení a zápisu. Režim WAL ale neumožňuje změny velikosti stránky, přidá do databáze další přidružení souborů a přidá další operaci vytváření kontrolních bodů.

Pokud chcete v SQLite.NET povolit WAL, zavolejte EnableWriteAheadLoggingAsync metodu v SQLiteAsyncConnection instanci:

await Database.EnableWriteAheadLoggingAsync();

Další informace najdete v tématu SQLite Write-Ahead Logging on sqlite.org.

Kopírování databáze

Existuje několik případů, kdy může být nutné zkopírovat databázi SQLite:

  • Databáze byla dodána s vaší aplikací, ale musí být zkopírována nebo přesunuta do zapisovatelného úložiště na mobilním zařízení.
  • Potřebujete vytvořit zálohu nebo kopii databáze.
  • Potřebujete vytvořit verzi, přesunout nebo přejmenovat soubor databáze.

Obecně platí, že přesouvání, přejmenování nebo kopírování souboru databáze je stejný proces jako jakýkoli jiný typ souboru s několika dalšími aspekty:

  • Před pokusem o přesunutí souboru databáze by se měla zavřít všechna připojení k databázi.
  • Pokud použijete protokolování s předstihem, SQLite vytvoří soubor sdíleného přístupu k paměti (.shm) a (zapsat hlavičkový protokol) (.wal). Ujistěte se, že u těchto souborů použijete také všechny změny.

Další informace naleznete v tématu Zpracování souborů v Xamarin.Formssouboru .