mcpField
M
maui-sqlite-database

maui-sqlite-database

github.com/davidortinau数据与数据库17650 次安装16 周前更新
代码仓库

关于 maui-sqlite-database

面向 .NET MAUI 应用的 SQLite 开发技能,整理平台差异与数据库实现要点,涵盖连接生命周期、路径、并发和性能。

主要功能

  1. 01跨平台数据库路径建议
  2. 02单例连接与延迟初始化
  3. 03WAL 模式与并发指导
  4. 04安全执行数据库文件操作
  5. 05查询与批量写入优化建议

适用场景

  1. 01选择适用于 MAUI 平台的数据库路径
  2. 02避免重复连接导致数据损坏
  3. 03规划批量写入和大表查询

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/davidortinau/maui-skills --skill maui-sqlite-database

安装后在 Claude Code 中输入/maui-sqlite-database确认已加载。

附带文件references/sqlite-database-api.md

详细介绍

SQLite 数据库 — 注意事项与最佳实践

有关完整的服务实现、常量、数据模型模板和常见模式,请参阅 references/sqlite-database-api.md。

⚠️ 错误的包选择陷阱


<PackageReference Include="Microsoft.Data.Sqlite" />
<PackageReference Include="sqlite-net" />
<PackageReference Include="SQLitePCL.raw" />


<PackageReference Include="sqlite-net-pcl" Version="1.9.*" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.*" />

常见错误

❌ 使用 Environment.GetFolderPath 获取数据库路径
// ❌ Not cross-platform safe — fails on some MAUI targets
var path = Path.Combine(Environment.GetFolderPath(
    Environment.SpecialFolder.LocalApplicationData), "app.db3");

// ✅ Use FileSystem.AppDataDirectory for all MAUI platforms
var path = Path.Combine(FileSystem.AppDataDirectory, "app.db3");
❌ 创建多个 SQLiteAsyncConnection 实例

多个指向同一文件的 SQLiteAsyncConnection 实例不是线程安全的。通过 DI 单例使用同一个实例:

// ❌ Creating new connections per request
public async Task<List<Item>> GetItems()
{
    var db = new SQLiteAsyncConnection(Constants.DatabasePath);
    return await db.Table<Item>().ToListAsync();
}

// ✅ Lazy singleton — one connection, created once
private SQLiteAsyncConnection? _database;
private async Task<SQLiteAsyncConnection> GetDatabaseAsync()
{
    if (_database is not null) return _database;
    _database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
    await _database.ExecuteAsync("PRAGMA journal_mode=WAL;");
    await _database.CreateTableAsync<TodoItem>();
    return _database;
}
❌ 忘记启用 WAL 模式

未启用 WAL 时,读取操作会阻塞写入操作。初始化时务必启用:

await _database.ExecuteAsync("PRAGMA journal_mode=WAL;");
❌ 对已打开的数据库执行文件操作
// ❌ Moving/deleting while connection is open — data corruption
File.Delete(Constants.DatabasePath);

// ✅ Always close first
await databaseService.CloseConnectionAsync();
if (File.Exists(Constants.DatabasePath))
    File.Delete(Constants.DatabasePath);

平台注意事项

平台注意事项
iOSFileSystem.AppDataDirectory 由 iCloud 备份 — 使用 FileSystem.CacheDirectory,将数据库排除在 iCloud 备份之外
所有平台多个 SQLiteAsyncConnection 实例指向同一文件 → 数据损坏
所有平台未启用 WAL → 读取操作阻塞写入操作,并发性能不佳
所有平台对已打开的数据库执行文件操作 → 数据损坏

决策指南

问题建议
DI 生命周期?单例 — 使用一个连接,WAL 负责处理并发读取
WAL 模式?始终启用 — 在移动设备上没有理由不启用
数据库路径?FileSystem.AppDataDirectory — 绝不要使用 Environment.GetFolderPath
保存模式?检查 Id != 0 → 更新,否则插入
多个表?在延迟初始化中添加所有 CreateTableAsync<T>() 调用
需要导出/备份?先关闭连接,然后调用 File.Copy

性能提示

  1. 批量写入时使用事务 — 单独插入速度较慢;使用 RunInTransactionAsync 包裹
  2. 为经常查询的列添加 [Indexed] — 尤其是外键
  3. WAL 模式可消除读取与写入之间的争用
  4. 避免对大型表使用 ToListAsync() — 使用 Where() 筛选并分页
  5. 复杂查询使用原始 SQL — 对于联接,QueryAsync<T> 比链式 LINQ 更快

检查清单

  • 安装 sqlite-net-pcl + SQLitePCLRaw.bundle_green(而不是 Microsoft.Data.Sqlite)
  • 数据库路径使用 FileSystem.AppDataDirectory
  • 模型带有 [PrimaryKey, AutoIncrement]
  • 使用单个 DatabaseService,采用延迟异步初始化模式
  • 通过 PRAGMA journal_mode=WAL 启用 WAL
  • 在 DI 中将 DatabaseService 注册为单例
  • 移动、复制或删除任何文件之前关闭连接
  • iOS:如有需要,将数据库排除在 iCloud 备份之外

评论

支持 Markdown