[官网文档翻译]Flutter持久化库drift - 高级特性 - 自定义数据行类

8,795 阅读4分钟

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

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

本文翻译自 drift 的 官方文档 Custom row classes (simonbinder.eu)

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


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

自定义数据行类

使用自定义类做为 drift 表的数据行类。

对于在 Dart 中或 drift 文件中声明的每个表, drift_dev 会生成一个(数据)行类(有时也被称为数据类),用来为更新和插入保有一个完整的数据行或其姊妹类。这能正常对应大多数情况: drift 知道表中有多少列,能为所有列生成一个简单的类。尽管如此,一些情况下,也可能想要定制生成的类。例如:想要添加一个 mixin , 用来扩展另一个类或接口,或者使用 json_serilaizable 之类的构建器来定制如何序列化成 json 。

从 moor 的4.3版本(和drift)开始,使用自定义类作为数据类。

使用自定义类

要使用自定义数据行类,只需简单地在表定义上添加注解 @UseRowClass

@UseRowClass(User)
class Users extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text()();
  DateTimeColumn get birthday => dateTime()();
}

class User {
  final int id;
  final String name;
  final DateTime birthDate;

  User({required this.id, required this.name, required this.birthDate});
}

一个数据行类(非自定义)必须带着以下必要项目:

  • 必须有一个未命名的构造方法
  • 每个构造方法参数必须有一个 drift 列的列名(匹配在表定义中的 getter 名称)
  • 构造方法的参数类型必须和列的类型相同,包括是否可空和已应用的类型转换器。

另一方面,注意这些:

  • 一个自定义数据行类可以有附加的字段和构造方法参数,只要它们不是 required (必需的)。 drift 在映射到数据库的行时会忽略这些参数。
  • 一个表可以有未反映到自定义数据行类里的附加列。 drift 在匹配数据行时会不加载这些列。

使用另外一个构造方法

默认情况下,drift 会使用默认的、未命名的构造方法来映射一个数据行到类。如果想要使用另外一个构造方法,在 @UseRowClass 注解中设置 constructor 参数。

@UseRowClass(User, constructor: 'fromDb')
class Users extends Table {
  // ...
}

class User {
  final int id;
  final String name;
  final DateTime birthDate;

  User.fromDb({required this.id, required this.name, required this.birthDate});
}

drift 文件中存在的行

要使用 drift 文件中的存在的数据行类,需要在表声明的末尾使用 WITH 关键字。也不要忘了引入声明数据行类的 Dart 文件到 drift 文件中。

import 'user.dart'; -- 或者其它 Dart 文件名

CREATE TABLE users(
  id INTEGER NOT NULL PRIMARY KEY,
  name TEXT NOT NULL,
  birth_date DATETIME NOT NULL
) WITH User;

用自定义(数据行)类插入和更新

大多数情况下,生成的姊妹数据行类是用来更新和插入的正确工具。如果更想用自定义的数据行类来插入,只需要实现 Insertable , T 是你的自定义数据行类自身。例如:前面的类可以改为这样:

class User implements Insertable<User> {
  final int id;
  final String name;
  final DateTime birthDate;

  User({required this.id, required this.name, required this.birthDate});

  @override
  Map<String, Expression> toColumns(bool nullToAbsent) {
    return UsersCompanion(
      id: Value(id),
      name: Value(name),
      birthDate: Value(birthDate),
    ).toColumns(nullToAbsent);
  }
}

何时使用自定义(数据行)类是明智的

drift 默认生成的类的内容对于大多数应用来说是不错的默认内容。可是在一些高级使用情况下,自定义类会是个更好的替代方案:

  • 减少生成代码的大小:因为历史原因和向后兼容性, drift 类包含很多用于 json 序列化的方法和 copyWith ,这些方法并不是对所有用户都是必需的。这种情况下使用自定义数据行类可以减少代码的膨胀。
  • 自定义父类:一个自定义数据行类可以用来扩展、归类和实现或者根据需要 mix-in (混入)其他类
  • 其它代码生成器:因为是由你来控制(数据行)类,所以可以更好地利用其它构建器如 json_serializable 或者 built_value

限制

这些限制会在即将来到的 drift 版本中逐渐去掉。可跟踪此 issue 查看详细内容。

现在,本特性会受以下限制影响:

  • 在 drift 文件中,只能使用默认的未命名的构造方法。
  • 自定义数据行类只能用表,不能用来定制编译后查询的结果集。