「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。
Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)
本文翻译自 drift 的 官方文档 Many to many relationships (simonbinder.eu)。
肉翻多有不足,不吝赐教。
常见问题
使用数据库
如果已经跟着开始指南创建了一个 MyDatabase
类。建议只有一个数据库的实例(单例),这样可以将这个实例存储为一个全局变量:
简单的 Flutter
MyDatabase database;
void main() {
database = MyDatabase();
runApp(MyFlutterApp());
}
为此使用 InheritedWidgets
会更简洁,provider
包在这里会起帮助作用:
Provider
如果正在使用 provider 包,可以将高级别组件包装进 provider 来管理数据库实例:
void main() {
runApp(
Provider<MyDatabase>(
create: (context) => MyDatabase(),
child: MyFlutterApp(),
dispose: (context, db) => db.close(),
),
);
}
可以使用 Provider.of(context)
在之后的处理中使用组件来访问数据库。
一个更复杂的架构
如果想严格保持组件层外的业务逻辑,可能会使用一些依赖注入框架如 kiwi
或 get_it
来实例化服务和视图模型( view model )。
因此在最想用的 Flutter 依赖注入框架中创建 MyDatabase
的实例会解决这个问题。
为什么有这么多表错误?
如果在安装应用之后添加了另外一个表,需要对新加的表编写一个迁移。如果是在开发应用的过程中,要卸载-重装应用也是可以的。请注意,在 Android 的一些设备上应用的数据可能会被备份,所以手动删除应用的数据而不是重新安装是有必要的。
如何修复生成文件中的提示?
基于你的提示设定,在 drift 生成的 .g.dart
文件中可能会看到一些警告。因为提示主要用于手写代码,所以建议对生成的文件禁用静态分析。对于这个问题,可以在工程下生成一个顶级的文件名为 analysis_options.yaml
,然后添加下面的内容:
analyzer:
exclude:
- "**/*.g.dart"
可能需要重启 IDE 以应用改变。
如何检查生成的 sql ?
所有的数据库实现( NativeDatabase
、 FlutterQueryExecutor
、 等) 都有一个 logStatements
参数,可以设置为 true
。当为 true
时,drift 会在运行时打印语句。
如何在 APP 第一次启动时插入数据?
可以用自定义的迁移策略在 APP 第一次启动时构成数据库。要在数据库创建时插入数据(通常是在 APP 第一次运行时发生),可以使用如下方式:
MigrationStrategy(
onCreate: (m) async {
await m.createAll(); // 创建所有的表
await into(myTable).insert(...); // 第一次运行时插入
}
)
甚至可以在 onCreate
回调中使用事务或批处理。
另外一个方式是在应用的 asset 中包含一个事先构成的数据库,然后使用这个数据库:
QueryExecutor databaseWithDefaultAsset(File file, String asset) {
// LazyDatabase 让们可以作一些异步初始化的工作。
return LazyDatabase(() async {
if (!await file.exists()) {
// 数据库不存在,使用 asset 中的默认数据库
final content = await rootBundle.load(asset);
await file.parent.create(recursive: true);
await file.writeAsBytes(content.buffer.asUint8List(0));
}
});
}
drift 和 X 相比如何?
现在有各种各样的用于 Dart 和 Flutter 的好的持久化库
这里有一个好用的库和 drift 比较的不完整(显然也是片面的)的列表。 如果你有任何这些库(或其它库)的经验,也想分享一下和 drift 的比较,邀请你来贡献此页。
sqflite 、 sqlite3
sqflite 是在 iOS 和安卓上绑定了 sqlite api 的 Flutter 包。现在也在正常维护,具有稳定的 api 。事实上,moor_flutter
的变体(?)是基于 sqflite 的。这是即便这样,sqflite 也有一个在 Dart 中构建一些简单查询的 api,drift 通过下面的内容更进了一步:
- 为查询生成类型安全的映射代码
- 为查询提供自动更新的流
- 管理
CREATE_TABLE
语句和大多数 schema 迁移 - 暴露查询的更顺畅的 api
大多数 APP 仍然不需要这些特性,sqlite 会是一个非常合适的持久化库。
同样的也适用于 sqlite3
包 - package:drift/native.dart
使用了这个库,但是在上层提供了一些附加服务。
sqlcool
sqlcool 是一个和 sqflite 差不多的轻量库,可以简化查询编写和 schema 管理 ,它也有自动更新的流。如果不想(不需要)用 drift 生成代码来解析查询的结果,它可以作为一个相当好的替代方案。
floor
floor 也有很多如自动更新流和 schema 迁移的方便的特性。和 drift 类似,在 Dart 中定义数据库的结构,然后在 sql 中写查询 - 如果生成了映射代码。 drift 也有类似的特性,但是它还可以在编译时验证查询是否是有效的。 drift 还有一个代替 sql 可以在 dart 中写查询的功能。
两者之间的一个不同点是 floor 让你写你自己的类,然后基于写的类生成映射代码。默认,drift 会为你生成大部分类,这更便于使用,但是在一些情况下会使 api 缺少弹性。 drift 还可以使用 自定义数据行类。
firebase
实时数据库和云端数据存储都便于使用持久化库,可以用来在设备间同步,即使设备离线。两者都有自动更新流的特性和一个简单的查询 api 。无论如何,它们都不是关系数据库,所以他们不支持如 聚集函数、结合、复杂过滤这样有用的 sql 特性。
有下面的情形时,firebase 是一个很好的选项:
- 数据模型使用文档表达而不是关系型
- 不需要有自己的后端,但是需要同步数据。
能查看一个 drift 数据库吗?
是的! drift 在 sqlite3 数据库文件中存储数据,sqlite3 数据库文件可以从设备上提取和在本地查阅。
要直接在设备上查阅一个数据库,可以使用由 Koen Van Looveren 开发的moor_db_viewer
包。