[官网文档翻译]Flutter持久化库drift - 开始指南(使用sql)

3,282 阅读4分钟

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」。

Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)

本文翻译自 drift 的 官方文档 Getting started with sql (simonbinder.eu)

肉翻多有不足,不吝赐教。


重要通知: moor 已改名为 drift 。更多信息[中文]。

使用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 在构建过程中生成了什么:

  • 生成数据类(TodoCategory )- 这些类保有各自表的单个数据行。
  • 这些类的姊妹版。这些只在使用 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 。这里有进一步的指南来帮助你学到更多。