我正在使用本地数据库(带有 Drift 的 SQLite) 来保存状态。 存储库读取数据并将数据写入数据库,并且应通过其API提供相应的模型。
因此,数据库返回一个 DataClass 对象,我需要 将此数据映射到我的 ModelClass。在存储库中的每个方法中手动进行映射很烦人且容易出错,并且向模型本身添加某种“fromDataClass”和“toDataClass”感觉是错误的,因为模型应该从具体的数据库实现中抽象出来(因此不需要知道它的存储位置)。
但是 Drift 提供了对 TypeConverters 的支持(https://drift.simonbinder.eu/docs/advanced-features/type_converters/),我不确定这是否是正确的方法? 当数据来自本地数据库时,处理数据映射的最佳方式是什么?
您提到的类型转换器用于通过将不支持的数据类型编码为 JSON 或转换器中指定的任何自定义格式来存储它们。但是,这种方法无助于将域类映射到数据类或从数据类映射。
您正在寻找的是自定义行类。
通过创建表并用
@UseRowClass(YourCustomRowClass)
注释,数据类不会自动生成;相反,将使用您的自定义类。
例如
@UseRowClass(TaskLocalDto)
class Tasks extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text()();
}
这有什么帮助? 定义自己的数据类使您可以灵活地定义自定义方法、使用 mixin、扩展其他类等。考虑到这一点,我们可以使用
fromDomain
和 toDomain
创建自定义类像这样的方法:
class TaskLocalDto {
TaskLocalDto({
required this.id,
required this.name,
});
final int id;
final String name;
factory TaskLocalDto.fromDomain(Task task) => TaskLocalDto(
id: task.id,
name: task.name,
);
Task toDomain() => Task(
id: id,
name: name,
);
}
现在这个类将成为您从数据库读取时的返回类型。以下方法将返回
TaskLocalDto
:
select(tasks).get();
然后您可以在 DAO 中包含这样的方法:
@DriftAccessor(tables: [Tasks])
class TasksDao extends DatabaseAccessor<AppDatabase> with _$TasksDaoMixin {
TasksDao(this.db) : super(db);
final AppDatabase db;
Future<List<TaskLocalDto>> getTasks() async {
return select(tasks).get();
}
}
这适用于读取数据。但是,如果您想使用自定义数据类写入数据,则需要执行额外的步骤。写入数据库需要使用Companion类。 官方漂移文档解释了为什么需要这个额外的课程:
对于部分数据,更喜欢使用同伴。在上面的例子中,我们 仅设置类别列,因此我们使用了同伴。这是为什么 必要的?如果一个字段设置为空,我们不知道我们是否 需要在数据库中将该列设置回空,或者我们是否应该 保持不变即可。同伴中的领域有一个特殊的 Value.absent() 状态使得这一点变得明确。
要使自定义数据类充当伴生类,您需要实现
Insertable<TaskLocalDto>
并重写 Map<String, Expression> toColumns(bool nullToAbsent)
方法。
我们之前的课程现在看起来像这样:
class TaskLocalDto implements Insertable<TaskLocalDto> {
TaskLocalDto({
required this.id,
required this.name,
});
final int id;
final String name;
factory TaskLocalDto.fromDomain(Task task) => TaskLocalDto(
id: task.id,
name: task.name,
);
Task toDomain() => Task(
id: id,
name: name,
);
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
return TasksCompanion(
id: Value(id),
name: Value(name),
).toColumns(nullToAbsent);
}
}
现在,此方法将允许使用自定义类进行插入操作,并且您可以将其添加到上一个示例中的 DAO 中:
Future<void> insertTask(TaskLocalDto task) async {
await into(tasks).insert(task);
}
提示: 如果您的数据类具有可为空值,请在重写
Value.absentIfNull()
方法时使用 Value()
而不是 toColumns()
。
您的自定义数据类现在将与您的数据库一起使用,您可以将
toDomain
和 fromDomain
与它一起使用:
final taskDto = TaskLocalDto.fromDomain(task);
或
final task = taskDto.toDomain();