「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」。
Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)
本文翻译自 drift 的 官方文档 Getting started with sql (simonbinder.eu)。
肉翻多有不足,不吝赐教。
使用sql
学习一下如何开始使用 drift 的 sql 版,或者如何从一个现有的工程迁移到 drift 。
常规的使用指南(中文)阐述了如何在 dart 中通过声明表和查询来开始使用 drift 。现在的( sql ) 版本则聚焦于如何通过 sql 来使用 drift。
添加依赖
本部分内容和 [官网文档翻译]Flutter持久化库drift - 简介 - 掘金 (juejin.cn)](juejin.cn/post/703020…) 中的相关内容一致,不再重复翻译。
声明表和查询
在 sql 中声明表和查询,需要创建一个 tables.drift
的文件,放在 dart 文件的同目录下(例:lib/database/table.drift
)。
可以把查询用的 CREATE TABLE
语句放在该文件中。接下来的例子会创建两个表来给 Todo-APP 建模。如果你正在将现有的工程迁移到 drift
,你只需要把现有的 CREATE TABLE
语句复制到该文件中。
tables.drift:
-- tables.drift 文件
CREATE TABLE todos (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT,
body TEXT,
category INT REFERENCES categories (id)
);
CREATE TABLE categories (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
description TEXT
) AS Category; -- 下面有 "AS Category" 的说明
/* 创建表后,可以把查询放进来。
只需要写出查询名、:(冒号) 和 SQL。 */
todosInCategory: SELECT * FROM todos WHERE category = ?;
/ 这里有一个复杂些的查询。
它会对每个 category 进行实体的计数,计数的值在这些实体中,并不在任何 category 中。*/
countEntries:
SELECT
c.description,
(SELECT COUNT(*) FROM todos WHERE category = c.id) AS amount
FROM categories c
UNION ALL
SELECT null, (SELECT COUNT(*) FROM todos WHERE category IS NULL)
关于 AS Category
drift 会为表创建 dart 类,这些类的类名是基于表名的。 默认情况下,drift 只是把表名后的
s
去掉。 大多数情况下这是可行的,但是某些情况(像上面的categories
表)下是无法正常处理的。 我们是想生成Category
类,而不是Categorie
,所以我们需要在语句的末尾加一个AS
声明来告诉 drift 生成一个不同的表名。
生成匹配代码
声明表之后,我们来生成一些实际用来执行的 dart 代码。drift 需要知道哪些表在数据库中被使用,所以我们需要写一个小的 dart 类,然后 drift 会读取这个类。在前一步创建的 tables.drift
的同目录下创建一个名为 database.dart
的文件。
import 'dart:io';
import 'package:drift/drift.dart';
// 下面这些 import 仅用于打开数据库。
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'database.g.dart';
@DriftDatabase(
// .drift文件相关的 import , drift 也支持 `package:` 的 import
include: {'tables.drift'},
)
class AppDb extends _$AppDb {
AppDb() : super(_openConnection());
@override
int get schemaVersion => 1;
}
LazyDatabase _openConnection() {
// LazyDatabase 工具类可以让我们找一个合适的位置来存放异步文件。
return LazyDatabase(() async {
// 在 Documents 目录存放名为 db.sqlite 的数据库文件。
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
return NativeDatabase(file);
});
}
在命令行执行 flutter pub run build_runner build
命令生成包含 _$AppDb
父类的 database.g.dart
文件。
drift 生成了什么
来看一下 drift 在构建过程中生成了什么:
- 生成数据类(
Todo
和Category
)- 这些类保有各自表的单个数据行。 - 这些类的姊妹版。这些只在使用 dirft 的 dart API 时有关联。更多内容可以查看这里。
- 一个
CountEntriesResult
类,这个类保有运行countEntries
查询后的结果数据行。 - 一个
_$AppDb
父类。这个类会在数据库文件首次打开时负责创建表。它也包含在tables.drift
文件中声明的查询所对应的类型安全的方法:- 一个
Selectable todosInCategory(int)
方法,用来执行上面声明的todosInCategory
查询。 drift 已将查询的变量类型设为int
,因为这是用于( where )比较的category
列的类型。
方法返回一个Selectable
, 用来标示它可以用作常规查询(Selectable.get
返回Future
),或用作自动更新的流(用.watch
代替.get()
)。 - 一个
Selectable countEntries()
方法,使用时用来执行其它查询。
- 一个
顺便说下,也可以把插入、更新和删除语句放在 .drift
文件中。drift 也会为它们生成匹配的代码。
学习更多
现在你已经知道了如何在 drift 中共用 sql 。这里有进一步的指南来帮助你学到更多。
- SQL IDE 为编辑器中的 sql 查询提供反馈。
- 事务
- Schema 迁移
- 在 Dart 中编写查询和表达式
- 一个关于
drift
文件的深入的指南,阐述了 impport 语句还有 Dart-SQL 的交互。