「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。
Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)
Flutter的持久化库 moor 已更名为 drift,肉翻一下 drift 的开始文档。
drift pub: drift | Dart Package (pub.dev)
drift 官网文档: Documentation & Guides (simonbinder.eu)
drift 简介
drift 是一个用于 Dart&Flutter 应用的响应式持久化库。(响应式?这个地方有些迷糊。)
它是建立在像 sqlite 或 sql.js 类似的数据库的库之上,并提供一些特性,如:
- 类型安全: 代替手动写 SQL 查询,解析查询返回的 List,drift 把 rows 转换成选用的对象。
- 流查询:drift 无需额外处理便可以监视你的查询。任何查询都可以转换为自动更新流,当基础数据发生改变时,该流会发出新的项目。(即基础数据发生改变,查询结果也会自动更新。)
- 流畅的查询:drift生成 dart 的 api,可以用来写查询,并自动获取结果。只用
select(users).watch()就可以保持所有用户的更新后的列表。就是这样!无需写 SQL,无需解析 rows。 - 类型安全 SQL:如果你更喜欢写 SQL,那也 OK!drift 内置有SQL 解析器 和 分析器。它可以在编辑时解析你的查询,整理出要返回的数据列并生成表示 rows 的 dart 代码。
- 迁移工具:drift 提供了如
.createAllTables()的工具函数使写迁移处理更容易。无需手动写CREATE TABLE语句,就能保持表的更新。
还有更多!drift 会在插入数据前检验数据,所以能够收到有帮助的错误信息,而不只是SQL 错误码。当然,它也支持事务,支持 DAO,还有高效的批量插入语句。
开始使用drift
注:如果你更喜欢看指导视频,Reso Video 制作了一个详细的视频来解释如何开始。可在这里观看视频。(油管视频,你懂的。)
添加依赖
首先,添加 drift 依赖到工程的 pubspec.yaml。
drift 的当前版本是 pub v1.0.1,drift_dev 的最新版本是 pub v1.0.2。
dependencies:
drift: ^1.0.1
sqlite3_flutter_libs: ^0.5.0
path_provider: ^2.0.0
path: ^1.8.0
dev_dependencies:
drift_dev: ^1.0.2
build_runner: ^2.1.4
如果想知道为什么有这么多必需依赖,这有一个各个依赖用途的概览:
- drift: 定义了绝大部分 API 的核心包。
- sqlite3_flutter_libs: 承载 Android 或 iOS App 上的 sqlite3的最新版本。如果不使用Flutter,这不是必需的。但之后你需要自己把 sqlite3 包含进来。
- path_provide 和 path: 用来发现一个合适的位置来存放数据库,由 Flutter&Dart 团队维护。
- drift_dev: 这个依赖只在开发环境使用,用来基于表生成查询代码。不会包含在最终的APP中。
- build_runner: 代码生成用的实用工具,由 Dart 团队维护。
切换到 moor/ffi 前一版本的文档建议使用 moor_flutter 或 moor_ffi 包。对于新用户,建议使用 package:moor/ffi.dart 来打开数据库。更多信息参照下文。
一些版本的 Flutter 工具在 Android 上创建了一个不兼容的 setting.gradle,使用 moor_ffi 会造成问题。如果出现了 Failed to load dynamic library异常,看下这个评论。
声明表
使用 drift, 可以用简单的 Dart 代码基于表结构创建 Model。
import 'package:drift/drift.dart';
// assuming that your file is called filename.dart. This will give an error at first,
// but it's needed for drift to know about the generated code
part 'filename.g.dart';
// this will generate a table called "todos" for us. The rows of that table will
// be represented by a class called "Todo".
class Todos extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()();
}
// This will make drift generate a class called "Category" to represent a row in this table.
// By default, "Categorie" would have been used because it only strips away the trailing "s"
// in the table name.
@DataClassName("Category")
class Categories extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text()();
}
// this annotation tells drift to prepare a database class that uses both of the
// tables we just defined. We'll see how to use that database class in a moment.
@DriftDatabase(tables: [Todos, Categories])
class MyDatabase {
}
注意: 列定义、表名和主键在编译时必须是已知的。对于列定义和主键,函数必须使用 =>操作符,并且不能包含多于文档和示例中包括的内容。否则,代码生成器会无法识别处理。
生成代码
drift 集成了 Dart的 构建系统,所以可以用flutter packages pub run build_runner build 生成全部代码。如果代码改变时,想要持续地编译生成的代码。可以运行 flutter packages pub run build_runner watch 来代替。执行过一次前面的一种命令之后,drift生成器会创建数据库和数据的实体类。使用时,如下修改 MyDatabase 类.
// These imports are only needed to open the database
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:drift/drift.dart';
import 'dart:io';
LazyDatabase _openConnection() {
// the LazyDatabase util lets us find the right location for the file async.
return LazyDatabase(() async {
// put the database file, called db.sqlite here, into the documents folder
// for your app.
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
return NativeDatabase(file);
});
}
@DriftDatabase(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
// we tell the database where to store the data with this constructor
MyDatabase() : super(_openConnection());
// you should bump this number whenever you change or add a table definition. Migrations
// are covered later in this readme.
@override
int get schemaVersion => 1;
}
祝贺你!现在你已经为使用 drift 的全部功能做好了准备。