SQLite 数据库引擎允许 .NET 多平台应用 UI (.NET MAUI) 应用在共享代码中加载和保存数据对象。 可以按照以下步骤将 SQLite.NET 集成到 .NET MAUI 应用中,以在本地数据库中存储和检索信息:

  • 安装 NuGet 包
  • 配置常量
  • 创建数据库访问类
  • 访问数据
  • 高级配置
  • 示例应用使用 SQLite 数据库表来存储 todo 项。

    安装 SQLite NuGet 包

    使用 NuGet 包管理器搜索 sqlite-net-pcl 包,并将最新版本添加到 .NET MAUI 应用项目。

    许多 NuGet 包都有着类似的名称。 正确的包具有以下属性:

  • ID: sqlite net pcl
  • 作者:SQLite-net
  • 所有者:praeclarum
  • NuGet 链接: sqlite-net-pcl
  • 尽管包名称为 ,但请在 .NET MAUI 项目中使用 sqlite-net-pcl NuGet 包。

    SQLite.NET 是 praeclarum/sqlite-net 存储库 支持的第三方库。

    安装 SQLitePCLRaw.bundle_green

    除了 sqlite-net-pcl 之外,还需要 暂时 安装在每个平台上公开 SQLite 的基础依赖项:

  • Id: SQLitePCLRaw.bundle_green
  • 版本: 2.1.2
  • 作者: Eric Sink
  • 业主: Eric Sink
  • NuGet 链接: SQLitePCLRaw.bundle_green
  • 配置应用常量

    配置数据(如数据库文件名和路径)可以作为常量存储在应用中。 示例项目包括一个提供常见配置数据的 Constants.cs 文件:

    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 =>
            Path.Combine(FileSystem.AppDataDirectory, DatabaseFilename);
    

    在此示例中,常量文件指定用于初始化数据库连接的默认 SQLiteOpenFlag 枚举值。 枚举 SQLiteOpenFlag 支持以下值:

  • Create:连接将自动创建数据库文件(如果不存在)。
  • FullMutex:连接在序列化线程模式下打开。
  • NoMutex:连接在多线程模式下打开。
  • PrivateCache:即使已启用共享缓存,连接也不会参与共享缓存。
  • ReadWrite:连接可以读取和写入数据。
  • SharedCache:连接将参与共享缓存(如果已启用)。
  • ProtectionComplete:设备锁定时文件已加密且不可访问。
  • ProtectionCompleteUnlessOpen:文件在打开前会进行加密,但即使用户锁定设备,该文件仍可访问。
  • ProtectionCompleteUntilFirstUserAuthentication:在用户启动并解锁设备之前,文件将加密。
  • ProtectionNone:数据库文件未加密。
  • 可能需要根据数据库的使用方式指定不同的标志。 有关 的详细信息 SQLiteOpenFlags,请参阅在 sqlite.org 上打开新的数据库连接

    创建数据库访问类

    数据库包装类从应用的其余部分提取数据访问层。 此类集中了查询逻辑并简化了数据库初始化的管理,使随着应用的增长,可以更轻松地重构或扩展数据操作。 示例应用为此定义类 TodoItemDatabase

    延迟初始化

    使用 TodoItemDatabase 异步延迟初始化来延迟数据库的初始化,直到首次访问数据库,并使用类中的每个方法调用的简单 Init 方法:

    public class TodoItemDatabase
        SQLiteAsyncConnection Database;
        public TodoItemDatabase()
        async Task Init()
            if (Database is not null)
                return;
            Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
            var result = await Database.CreateTableAsync<TodoItem>();
    

    数据操作方法

    TodoItemDatabase 包括四种类型的数据操作方法:创建、读取、编辑和删除。 SQLite.NET 库提供了一个简单的对象关系映射 (ORM) ,使你无需编写 SQL 语句即可存储和检索对象。

    以下示例演示示例应用中的数据操作方法:

    public class TodoItemDatabase
        public async Task<List<TodoItem>> GetItemsAsync()
            await Init();
            return await Database.Table<TodoItem>().ToListAsync();
        public async Task<List<TodoItem>> GetItemsNotDoneAsync()
            await Init();
            return await Database.Table<TodoItem>().Where(t => t.Done).ToListAsync();
            // SQL queries are also possible
            //return await Database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
        public async Task<TodoItem> GetItemAsync(int id)
            await Init();
            return await Database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
        public async Task<int> SaveItemAsync(TodoItem item)
            await Init();
            if (item.ID != 0)
                return await Database.UpdateAsync(item);
                return await Database.InsertAsync(item);
        public async Task<int> DeleteItemAsync(TodoItem item)
            await Init();
            return await Database.DeleteAsync(item);
    

    TodoItemDatabase 可以注册为单一实例,如果使用依赖项注入,则可以在整个应用中使用该实例。 例如,可以使用 和 AddTransient 方法在 MauiProgram.csAddSingleton 中将页面和数据库访问类注册为 对象上的IServiceCollection服务:

    builder.Services.AddSingleton<TodoListPage>();
    builder.Services.AddTransient<TodoItemPage>();
    builder.Services.AddSingleton<TodoItemDatabase>();
    

    然后,这些服务可以自动注入到类构造函数中并访问:

    TodoItemDatabase database;
    public TodoItemPage(TodoItemDatabase todoItemDatabase)
        InitializeComponent();
        database = todoItemDatabase;
    async void OnSaveClicked(object sender, EventArgs e)
        if (string.IsNullOrWhiteSpace(Item.Name))
            await DisplayAlert("Name Required", "Please enter a name for the todo item.", "OK");
            return;
        await database.SaveItemAsync(Item);
        await Shell.Current.GoToAsync("..");
    

    或者,可以创建数据库访问类的新实例:

    TodoItemDatabase database;
    public TodoItemPage()
        InitializeComponent();
        database = new TodoItemDatabase();
    

    SQLite 提供了一个可靠的 API,其功能比本文和示例应用中介绍的功能更多。 以下部分介绍对可伸缩性非常重要的功能。

    有关详细信息,请参阅有关 sqlite.org 的 SQLite 文档

    预写日志记录

    默认情况下,SQLite 使用传统的回滚日志。 未更改的数据库内容的副本将写入单独的回滚文件,然后将更改直接写入数据库文件。 删除回滚日志时,将发生 COMMIT。

    Write-Ahead日志记录 (WAL) 首先将更改写入单独的 WAL 文件。 在 WAL 模式下,COMMIT 是追加到 WAL 文件的特殊记录,允许在单个 WAL 文件中发生多个事务。 WAL 文件在称为 检查点的特殊操作中合并回数据库文件。

    对于本地数据库来说,WAL 速度更快,因为读取器和编写器不会相互阻止,因此允许读取和写入操作并发。 但是,WAL 模式不允许更改 页面大小、向数据库添加其他文件关联以及添加额外的 检查点 操作。

    若要在 SQLite.NET 中启用 WAL,请在 实例上SQLiteAsyncConnection调用 EnableWriteAheadLoggingAsync 方法:

    await Database.EnableWriteAheadLoggingAsync();
    

    有关详细信息,请参阅 SQLite Write-Ahead sqlite.org 上的日志记录

    复制数据库

    在某些情况下,可能需要复制 SQLite 数据库:

  • 数据库已随应用程序一起提供,但必须复制或移动到移动设备上的可写存储。
  • 需要创建数据库的备份或副本。
  • 需要对数据库文件进行版本控制、移动或重命名。
  • 通常,移动、重命名或复制数据库文件的过程与任何其他文件类型相同,但需注意一些其他事项:

  • 在尝试移动数据库文件之前,应关闭所有数据库连接。
  • 如果使用 预写日志记录,SQLite 将创建共享内存访问 (.shm) 文件和 (预写日志) (.wal) 文件。 确保也对这些文件应用任何更改。
  •