Xamarin.Forms Místní databázeXamarin.Forms Local Databases

Stažení ukázky stažení ukázkyDownload Sample Download the sample

Databázový stroj SQLite umožňuje Xamarin.Forms aplikacím načíst a uložit datové objekty ve sdíleném kódu.The SQLite database engine allows Xamarin.Forms applications to load and save data objects in shared code. Ukázková aplikace používá k ukládání položek TODO tabulku databáze SQLite.The sample application uses a SQLite database table to store todo items. Tento článek popisuje, jak pomocí SQLite.Net ve sdíleném kódu ukládat a načítat informace v místní databázi.This article describes how to use SQLite.Net in shared code to store and retrieve information in a local database.

Snímky obrazovky aplikace ToDoList v iOS a AndroiduScreenshots of the Todolist app on iOS and Android

Integrujte SQLite.NET do mobilních aplikací pomocí následujících kroků:Integrate SQLite.NET into mobile apps by following these steps:

  1. Nainstalujte balíček NuGet.Install the NuGet package.
  2. Nakonfigurujte konstanty.Configure constants.
  3. Vytvořte třídu pro přístup k databázi.Create a database access class.
  4. Přístup k datům Xamarin.Forms v .Access data in Xamarin.Forms.
  5. Pokročilá konfigurace.Advanced configuration.

Instalace balíčku NuGet pro SQLiteInstall the SQLite NuGet package

Pomocí Správce balíčků NuGet vyhledejte SQLite-NET-PCL a přidejte nejnovější verzi do projektu sdíleného kódu.Use the NuGet package manager to search for sqlite-net-pcl and add the latest version to the shared code project.

Existuje několik balíčků NuGet s podobnými názvy.There are a number of NuGet packages with similar names. Správný balíček má tyto atributy:The correct package has these attributes:

  • ID: sqlite-net-pclID: sqlite-net-pcl
  • Autoři: SQLite-netAuthors: SQLite-net
  • Vlastníci: praeclarumOwners: praeclarum
  • Odkaz na NuGet: sqlite-net-pclNuGet link: sqlite-net-pcl

Poznámka

Bez ohledu na název balíčku použijte balíček NuGet -net-PCL NuGet, a to i v .NET Standard projektech.Despite the package name, use the sqlite-net-pcl NuGet package even in .NET Standard projects.

Konfigurace konstant aplikaceConfigure app constants

Ukázkový projekt obsahuje konstanty. cs soubor, který poskytuje běžná konfigurační data:The sample project includes a Constants.cs file that provides common configuration 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 konstanty určuje výchozí SQLiteOpenFlag hodnoty výčtu, které se používají k inicializaci připojení databáze.The constants file specifies default SQLiteOpenFlag enum values that are used to initialize the database connection. SQLiteOpenFlagVýčet podporuje tyto hodnoty:The SQLiteOpenFlag enum supports these values:

  • Create: Připojení vytvoří soubor databáze automaticky, pokud neexistuje.Create: The connection will automatically create the database file if it doesn't exist.
  • FullMutex: Připojení je otevřeno v režimu serializovaného vlákna.FullMutex: The connection is opened in serialized threading mode.
  • NoMutex: Připojení je otevřeno v režimu více vláken.NoMutex: The connection is opened in multi-threading mode.
  • PrivateCache: Připojení se ve sdílené mezipaměti neúčastní, a to ani v případě, že je povolené.PrivateCache: The connection will not participate in the shared cache, even if it's enabled.
  • ReadWrite: Připojení může číst a zapisovat data.ReadWrite: The connection can read and write data.
  • SharedCache: Připojení se bude podílet na sdílené mezipaměti, pokud je povolená.SharedCache: The connection will participate in the shared cache, if it's enabled.
  • ProtectionComplete: Soubor je zašifrovaný a nepřístupný v době, kdy je zařízení zamčené.ProtectionComplete: The file is encrypted and inaccessible while the device is locked.
  • ProtectionCompleteUnlessOpen: Soubor je zašifrovaný, dokud není otevřený, ale bude přístupný i v případě, že uživatel zamkne zařízení.ProtectionCompleteUnlessOpen: The file is encrypted until it's opened but is then accessible even if the user locks the device.
  • ProtectionCompleteUntilFirstUserAuthentication: Soubor je zašifrovaný, dokud se uživatel nespustí a zařízení neodemkne.ProtectionCompleteUntilFirstUserAuthentication: The file is encrypted until after the user has booted and unlocked the device.
  • ProtectionNone: Soubor databáze není zašifrovaný.ProtectionNone: The database file isn't encrypted.

V závislosti na způsobu, jakým se bude databáze používat, možná budete muset zadat jiné příznaky.You may need to specify different flags depending on how your database will be used. Další informace o najdete SQLiteOpenFlags v tématu otevření nového databázového připojení v sqlite.org.For more information about SQLiteOpenFlags, see Opening A New Database Connection on sqlite.org.

Vytvoření databázové třídy přístupuCreate a database access class

Obálková třída databáze vyabstrakce vrstvu přístupu k datům ze zbytku aplikace.A database wrapper class abstracts the data access layer from the rest of the app. Tato třída centralizace logiky dotazů a zjednodušuje správu inicializace databáze, což usnadňuje refaktoring a rozšiřování operací s daty při zvětšování aplikace.This class centralizes query logic and simplifies the management of database initialization, making it easier to refactor or expand data operations as the app grows. Aplikace TODO definuje TodoItemDatabase třídu pro tento účel.The Todo app defines a TodoItemDatabase class for this purpose.

Opožděná inicializaceLazy initialization

TodoItemDatabasePoužívá asynchronní opožděnou inicializaci reprezentovanou vlastní AsyncLazy<T> třídou pro odloženou inicializaci databáze, dokud není poprvé k dispozici:The TodoItemDatabase uses asynchronous lazy initialization, represented by the custom AsyncLazy<T> class, to delay initialization of the database until it's first accessed:

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

    //...
}

InstancePole se používá k vytvoření databázové tabulky pro TodoItem objekt, pokud ještě neexistuje, a vrátí TodoItemDatabase jako typ singleton.The Instance field is used to create the database table for the TodoItem object, if it doesn't already exist, and returns a TodoItemDatabase as a singleton. InstancePole typu AsyncLazy<TodoItemDatabase> je konstruováno při prvním čekání.The Instance field, of type AsyncLazy<TodoItemDatabase> is constructed the first time it's awaited. Pokud se více vláken pokusí o přístup k poli současně, všechny použijí jedinou konstrukci.If multiple threads attempt to access the field simultaneously, they will all use the single construction. Po dokončení konstrukce se pak všechny operace dokončí await .Then, when the construction completes, all await operations complete. Kromě toho všechny await operace po dokončení konstrukce pokračují ihned, protože je k dispozici její hodnota.In addition, any await operations after the construction is complete continue immediately since the value is available.

Poznámka

Připojení k databázi je statické pole, které zajišťuje, že se k životnímu cyklu aplikace používá jedno připojení k databázi.The database connection is a static field which ensures that a single database connection is used for the life of the app. Použití trvalého statického připojení nabízí lepší výkon než otevírání a zavírání připojení několikrát během relace jedné aplikace.Using a persistent, static connection offers better performance than opening and closing connections multiple times during a single app session.

Asynchronní opožděná inicializaceAsynchronous lazy initialization

Aby bylo možné spustit inicializaci databáze, vyhněte se zablokování spuštění a mít příležitost zachytit výjimky, ukázková aplikace používá asynchronní opožděné nepodařila reprezentované AsyncLazy<T> třídou:In order to start the database initialization, avoid blocking execution, and have the opportunity to catch exceptions, the sample application uses asynchronous lazy initalization, represented by the AsyncLazy<T> class:

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

AsyncLazyTřída kombinuje Lazy<T> typy a a Task<T> vytvoří opožděně inicializovaný úkol, který představuje inicializaci prostředku.The AsyncLazy class combines the Lazy<T> and Task<T> types to create a lazy-initialized task that represents the initialization of a resource. Delegát pro továrnu, který je předán konstruktoru, může být buď synchronní, nebo asynchronní.The factory delegate that's passed to the constructor can either be synchronous or asynchronous. Delegáti objektu factory se spustí ve vlákně fondu vláken a nebude proveden více než jednou (i když se více vláken pokusí spustit současně).Factory delegates will run on a thread pool thread, and will not be executed more than once (even when multiple threads attempt to start them simultaneously). Po dokončení delegáta továrny je k dispozici opožděně inicializovaná hodnota a všechny metody, které čekají na AsyncLazy<T> instanci, obdrží hodnotu.When a factory delegate completes, the lazy-initialized value is available, and any methods awaiting the AsyncLazy<T> instance receive the value. Další informace najdete v tématu AsyncLazy.For more information, see AsyncLazy.

Metody manipulace s datyData manipulation methods

TodoItemDatabaseTřída obsahuje metody pro čtyři typy manipulace s daty: vytvořit, číst, upravit a odstranit.The TodoItemDatabase class includes methods for the four types of data manipulation: create, read, edit, and delete. Knihovna SQLite.NET poskytuje jednoduchou relační mapu objektů (ORM), která umožňuje ukládat a načítat objekty bez psaní příkazů SQL.The SQLite.NET library provides a simple Object Relational Map (ORM) that allows you to store and retrieve objects without writing SQL statements.

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.FormsAccess data in Xamarin.Forms

TodoItemDatabaseTřída zpřístupňuje Instance pole, pomocí kterého lze vyvolat operace přístupu k datům ve TodoItemDatabase třídě:The TodoItemDatabase class exposes the Instance field, through which the data access operations in the TodoItemDatabase class can be invoked:

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

Pokročilá konfiguraceAdvanced configuration

SQLite poskytuje robustní rozhraní API s více funkcemi, než je zahrnuté v tomto článku a v ukázkové aplikaci.SQLite provides a robust API with more features than are covered in this article and the sample app. Následující části obsahují informace o funkcích, které jsou důležité pro škálovatelnost.The following sections cover features that are important for scalability.

Další informace najdete v dokumentaci k SQLite v sqlite.org.For more information, see SQLite Documentation on sqlite.org.

Protokolování před zápisemWrite-ahead logging

Ve výchozím nastavení používá SQLite tradiční deník vrácení zpět.By default, SQLite uses a traditional rollback journal. Kopie nezměněného obsahu databáze je zapsána do samostatného souboru vrácení se změnami, změny budou zapsány přímo do databázového souboru.A copy of the unchanged database content is written into a separate rollback file, then the changes are written directly to the database file. K potvrzení dojde při odstranění deníku vrácení.The COMMIT occurs when the rollback journal is deleted.

Protokolování Write-Ahead (WAL) zapisuje změny do samostatného souboru WAL jako první.Write-Ahead Logging (WAL) writes changes into a separate WAL file first. V režimu WAL je potvrzení speciálním záznamem připojeným k souboru WAL, který umožňuje výskyt více transakcí v jednom souboru WAL.In WAL mode, a COMMIT is a special record, appended to the WAL file, which allows multiple transactions to occur in a single WAL file. Soubor WAL se sloučí zpátky do databázového souboru ve speciální operaci nazvané kontrolní bod.A WAL file is merged back into the database file in a special operation called a checkpoint.

WAL může být pro místní databáze rychlejší, protože čtenáři a zapisovače se vzájemně neblokují, což umožňuje souběžné operace čtení a zápisu.WAL can be faster for local databases because readers and writers do not block each other, allowing read and write operations to be concurrent. Režim WAL však nepovoluje změny velikosti stránky, přidává do databáze další přidružení souborů a přidává další operaci kontrolního bodu .However, WAL mode doesn't allow changes to the page size, adds additional file associations to the database, and adds the extra checkpointing operation.

Chcete-li povolit WAL v SQLite.NET, volejte EnableWriteAheadLoggingAsync metodu v SQLiteAsyncConnection instanci:To enable WAL in SQLite.NET, call the EnableWriteAheadLoggingAsync method on the SQLiteAsyncConnection instance:

await Database.EnableWriteAheadLoggingAsync();

Další informace naleznete v tématu SQLite Write-Ahead Logging on sqlite.org.For more information, see SQLite Write-Ahead Logging on sqlite.org.

Kopírování databázeCopy a database

V některých případech může být nutné zkopírovat databázi SQLite:There are several cases where it may be necessary to copy a SQLite database:

  • Databáze byla dodávána s vaší aplikací, ale je nutné ji zkopírovat nebo přesunout do zapisovatelného úložiště v mobilním zařízení.A database has shipped with your application but must be copied or moved to writeable storage on the mobile device.
  • Musíte vytvořit zálohu nebo kopii databáze.You need to make a backup or copy of the database.
  • Je nutné, abyste si najmenovali, přesunuli nebo přejmenovali databázový soubor.You need to version, move, or rename the database file.

Obecně platí, že přesunutí, přejmenování nebo zkopírování databázového souboru je stejný proces jako jakýkoli jiný typ souboru s několika dalšími požadavky:In general, moving, renaming, or copying a database file is the same process as any other file type with a few additional considerations:

  • Před přesunutím souboru databáze by se měla zavřít všechna databázová připojení.All database connections should be closed before attempting to move the database file.
  • Použijete -li protokolování proti zápisu, SQLite vytvoří soubor přístupu ke sdílené paměti (. SHM) a soubor (. Wal) (s protokolem pro zápis).If you use Write-Ahead Logging, SQLite will create a Shared Memory Access (.shm) file and a (Write Ahead Log) (.wal) file. Ujistěte se, že jste všechny změny také použili v těchto souborech.Ensure that you apply any changes to these files as well.

Další informace najdete v tématu zpracování souborů v Xamarin.Forms .For more information, see File Handling in Xamarin.Forms.