Xamarin.Forms Bases de données localesXamarin.Forms Local Databases

Télécharger l’exemple Télécharger l’exempleDownload Sample Download the sample

Le moteur de base de données SQLite permet Xamarin.Forms aux applications de charger et d’enregistrer des objets de données dans du code partagé.The SQLite database engine allows Xamarin.Forms applications to load and save data objects in shared code. L’exemple d’application utilise une table de base de données SQLite pour stocker les éléments todo.The sample application uses a SQLite database table to store todo items. Cet article explique comment utiliser SQLite.Net dans du code partagé pour stocker et récupérer des informations dans une base de données locale.This article describes how to use SQLite.Net in shared code to store and retrieve information in a local database.

Captures d’écran de l’application ToDoList sur iOS et AndroidScreenshots of the Todolist app on iOS and Android

Intégrez SQLite.NET dans Mobile Apps en procédant comme suit :Integrate SQLite.NET into mobile apps by following these steps:

  1. Installez le package NuGet.Install the NuGet package.
  2. Configurez des constantes.Configure constants.
  3. Créer une classe d’accès à la base de données.Create a database access class.
  4. Accéder aux données Xamarin.Forms dans .Access data in Xamarin.Forms.
  5. Configuration avancée.Advanced configuration.

Installer le package NuGet SQLiteInstall the SQLite NuGet package

Utilisez le gestionnaire de package NuGet pour rechercher SQLite-net-PCL et ajouter la version la plus récente au projet de code partagé.Use the NuGet package manager to search for sqlite-net-pcl and add the latest version to the shared code project.

Il existe plusieurs packages NuGet portant des noms similaires.There are a number of NuGet packages with similar names. Le package correct possède ces attributs :The correct package has these attributes:

  • ID : sqlite-net-pclID: sqlite-net-pcl
  • Auteurs : SQLite-netAuthors: SQLite-net
  • Propriétaires : praeclarumOwners: praeclarum
  • Lien NuGet : sqlite-net-pclNuGet link: sqlite-net-pcl

Notes

Ne vous fiez pas au nom du package. Vous devez utiliser le package NuGet sqlite-net-pcl, même dans les projets .NET Standard.Despite the package name, use the sqlite-net-pcl NuGet package even in .NET Standard projects.

Configurer des constantes d’applicationConfigure app constants

L’exemple de projet inclut un fichier constants.cs qui fournit des données de configuration communes :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);
        }
    }
}

Le fichier constants spécifie les SQLiteOpenFlag valeurs d’énumération par défaut utilisées pour initialiser la connexion à la base de données.The constants file specifies default SQLiteOpenFlag enum values that are used to initialize the database connection. L' SQLiteOpenFlag énumération prend en charge les valeurs suivantes :The SQLiteOpenFlag enum supports these values:

  • Create: La connexion crée automatiquement le fichier de base de données, s’il n’existe pas.Create: The connection will automatically create the database file if it doesn't exist.
  • FullMutex: La connexion est ouverte en mode de thread sérialisé.FullMutex: The connection is opened in serialized threading mode.
  • NoMutex: La connexion est ouverte en mode multithread.NoMutex: The connection is opened in multi-threading mode.
  • PrivateCache: La connexion ne fait pas partie du cache partagé, même si elle est activée.PrivateCache: The connection will not participate in the shared cache, even if it's enabled.
  • ReadWrite: La connexion peut lire et écrire des données.ReadWrite: The connection can read and write data.
  • SharedCache: La connexion participera au cache partagé, si elle est activée.SharedCache: The connection will participate in the shared cache, if it's enabled.
  • ProtectionComplete: Le fichier est chiffré et inaccessible lorsque l’appareil est verrouillé.ProtectionComplete: The file is encrypted and inaccessible while the device is locked.
  • ProtectionCompleteUnlessOpen: Le fichier est chiffré jusqu’à ce qu’il soit ouvert, mais il est ensuite accessible même si l’utilisateur verrouille l’appareil.ProtectionCompleteUnlessOpen: The file is encrypted until it's opened but is then accessible even if the user locks the device.
  • ProtectionCompleteUntilFirstUserAuthentication: Le fichier est chiffré jusqu’à ce que l’utilisateur ait démarré et déverrouillé l’appareil.ProtectionCompleteUntilFirstUserAuthentication: The file is encrypted until after the user has booted and unlocked the device.
  • ProtectionNone: Le fichier de base de données n’est pas chiffré.ProtectionNone: The database file isn't encrypted.

Vous devrez peut-être spécifier des indicateurs différents selon la manière dont votre base de données sera utilisée.You may need to specify different flags depending on how your database will be used. Pour plus d’informations sur SQLiteOpenFlags , voir ouverture d’une nouvelle connexion de base de données sur sqlite.org.For more information about SQLiteOpenFlags, see Opening A New Database Connection on sqlite.org.

Créer une classe d’accès à la base de donnéesCreate a database access class

Une classe wrapper de base de données soustrait la couche d’accès aux données du reste de l’application.A database wrapper class abstracts the data access layer from the rest of the app. Cette classe centralise la logique de requête et simplifie la gestion de l’initialisation de la base de données, ce qui facilite la refactorisation ou le développement des opérations de données à mesure que l’application se développe.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. L’application todo définit une TodoItemDatabase classe à cet effet.The Todo app defines a TodoItemDatabase class for this purpose.

Initialisation tardiveLazy initialization

TodoItemDatabaseUtilise l’initialisation tardive asynchrone, représentée par la classe personnalisée AsyncLazy<T> , pour différer l’initialisation de la base de données jusqu’à son premier accès :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);
    }

    //...
}

Le Instance champ est utilisé pour créer la table de base de données pour l' TodoItem objet, s’il n’existe pas déjà, et retourne un TodoItemDatabase en tant que 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. Le Instance champ, de type, AsyncLazy<TodoItemDatabase> est construit la première fois qu’il est attendu.The Instance field, of type AsyncLazy<TodoItemDatabase> is constructed the first time it's awaited. Si plusieurs threads essaient d’accéder simultanément au champ, ils utilisent tous la construction unique.If multiple threads attempt to access the field simultaneously, they will all use the single construction. Ensuite, une fois la construction terminée, toutes les await opérations sont terminées.Then, when the construction completes, all await operations complete. De plus, toutes les await opérations ultérieures à la construction se poursuivent immédiatement, car la valeur est disponible.In addition, any await operations after the construction is complete continue immediately since the value is available.

Notes

La connexion de base de données est un champ statique qui garantit qu’une connexion de base de données unique est utilisée pendant la durée de vie de l’application.The database connection is a static field which ensures that a single database connection is used for the life of the app. L’utilisation d’une connexion statique permanente offre de meilleures performances que l’ouverture et la fermeture des connexions plusieurs fois pendant une session d’application unique.Using a persistent, static connection offers better performance than opening and closing connections multiple times during a single app session.

Initialisation tardive asynchroneAsynchronous lazy initialization

Pour démarrer l’initialisation de la base de données, éviter le blocage de l’exécution et avoir la possibilité d’intercepter des exceptions, l’exemple d’application utilise l’initialisation différée asynchrone, représentée par la AsyncLazy<T> classe :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> : Lazy<Task<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();
    }
}

La AsyncLazy classe combine les Lazy<T> Task<T> types et pour créer une tâche initialisée tardivement qui représente l’initialisation d’une ressource.The AsyncLazy class combines the Lazy<T> and Task<T> types to create a lazy-initialized task that represents the initialization of a resource. Le délégué de fabrique qui est passé au constructeur peut être synchrone ou asynchrone.The factory delegate that's passed to the constructor can either be synchronous or asynchronous. Les délégués d’usine s’exécutent sur un thread de pool de threads et ne sont pas exécutés plus d’une fois (même lorsque plusieurs threads essaient de les démarrer simultanément).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). Lorsqu’un délégué Factory se termine, la valeur initialisée tardivement est disponible et toutes les méthodes qui attendent l' AsyncLazy<T> instance reçoivent la valeur.When a factory delegate completes, the lazy-initialized value is available, and any methods awaiting the AsyncLazy<T> instance receive the value. Pour plus d’informations, consultez AsyncLazy.For more information, see AsyncLazy.

Méthodes de manipulation de donnéesData manipulation methods

La TodoItemDatabase classe comprend des méthodes pour les quatre types de manipulation de données : créer, lire, modifier et supprimer.The TodoItemDatabase class includes methods for the four types of data manipulation: create, read, edit, and delete. La bibliothèque SQLite.NET fournit un simple mappage relationnel objet (ORM) qui vous permet de stocker et de récupérer des objets sans écrire d’instructions 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);
    }
}

Accéder aux données dans Xamarin.FormsAccess data in Xamarin.Forms

La TodoItemDatabase classe expose le Instance champ, par l’intermédiaire duquel les opérations d’accès aux données dans la TodoItemDatabase classe peuvent être appelées :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();
}

Configuration avancéeAdvanced configuration

SQLite fournit une API robuste avec plus de fonctionnalités que celles décrites dans cet article et l’exemple d’application.SQLite provides a robust API with more features than are covered in this article and the sample app. Les sections suivantes couvrent les fonctionnalités qui sont importantes pour l’évolutivité.The following sections cover features that are important for scalability.

Pour plus d’informations, consultez la documentation SQLite sur sqlite.org.For more information, see SQLite Documentation on sqlite.org.

Journalisation avec écriture anticipéeWrite-ahead logging

Par défaut, SQLite utilise un journal de restauration traditionnel.By default, SQLite uses a traditional rollback journal. Une copie du contenu de la base de données inchangée est écrite dans un fichier de restauration distinct, puis les modifications sont écrites directement dans le fichier de base de données.A copy of the unchanged database content is written into a separate rollback file, then the changes are written directly to the database file. La validation se produit lorsque le journal de restauration est supprimé.The COMMIT occurs when the rollback journal is deleted.

La journalisation des Write-Ahead (WAL) écrit d’abord les modifications dans un fichier WAL distinct.Write-Ahead Logging (WAL) writes changes into a separate WAL file first. En mode WAL, une validation est un enregistrement spécial, ajouté au fichier WAL, qui permet à plusieurs transactions de se produire dans un seul fichier 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. Un fichier WAL est fusionné dans le fichier de base de données dans une opération spéciale appelée point de contrôle.A WAL file is merged back into the database file in a special operation called a checkpoint.

WAL peut être plus rapide pour les bases de données locales, car les lecteurs et les enregistreurs ne se bloquent pas mutuellement, ce qui permet d’effectuer des opérations de lecture et d’écriture simultanées.WAL can be faster for local databases because readers and writers do not block each other, allowing read and write operations to be concurrent. Toutefois, le mode WAL n’autorise pas les modifications apportées à la taille de la page, ajoute des associations de fichiers supplémentaires à la base de données et ajoute l’opération de point de contrôle supplémentaire.However, WAL mode doesn't allow changes to the page size, adds additional file associations to the database, and adds the extra checkpointing operation.

Pour activer WAL dans SQLite.NET, appelez la EnableWriteAheadLoggingAsync méthode sur l' SQLiteAsyncConnection instance :To enable WAL in SQLite.NET, call the EnableWriteAheadLoggingAsync method on the SQLiteAsyncConnection instance:

await Database.EnableWriteAheadLoggingAsync();

Pour plus d’informations, consultez SQLite Write-Ahead Logging on sqlite.org.For more information, see SQLite Write-Ahead Logging on sqlite.org.

Copier une base de donnéesCopy a database

Dans certains cas, il peut être nécessaire de copier une base de données SQLite :There are several cases where it may be necessary to copy a SQLite database:

  • Une base de données a été fournie avec votre application, mais elle doit être copiée ou déplacée vers un stockage accessible en écriture sur le périphérique mobile.A database has shipped with your application but must be copied or moved to writeable storage on the mobile device.
  • Vous devez effectuer une sauvegarde ou une copie de la base de données.You need to make a backup or copy of the database.
  • Vous devez modifier la version, déplacer ou renommer le fichier de base de données.You need to version, move, or rename the database file.

En général, le déplacement, le changement de nom ou la copie d’un fichier de base de données est le même processus que tout autre type de fichier, avec quelques remarques supplémentaires :In general, moving, renaming, or copying a database file is the same process as any other file type with a few additional considerations:

  • Toutes les connexions de base de données doivent être fermées avant de tenter de déplacer le fichier de base de données.All database connections should be closed before attempting to move the database file.
  • Si vous utilisez la journalisation en écriture anticipée, SQLite crée un fichier d’accès à la mémoire partagée (. fichier SHM) et un fichier (Journal d’écriture anticipée) (. Wal).If you use Write-Ahead Logging, SQLite will create a Shared Memory Access (.shm) file and a (Write Ahead Log) (.wal) file. Veillez également à appliquer toutes les modifications apportées à ces fichiers.Ensure that you apply any changes to these files as well.

Pour plus d’informations, consultez gestion des Xamarin.Forms fichiers dans .For more information, see File Handling in Xamarin.Forms.