Flutter代码生成插件dorm_generator的使用
dorm_generator
提供了与dORM框架配合使用的代码。
Getting started
在你的项目中运行以下命令:
dart pub add dev:dorm_generator
dart pub add dev:build_runner
dart pub add dev:json_serializable
dart pub get
Usage
注意:本文档假定你已经看过dorm_annotations文档。
Generating
在Dart项目的lib
文件夹中创建一个文件。例如,命名为lib/models.dart
。
编写类、getter及其注解到该文件中,并添加以下指令到文件顶部:
import 'package:dorm_annotations/dorm_annotations.dart';
import 'package:dorm_framework/dorm_framework.dart';
part 'models.g.dart';
part 'models.dorm.dart';
在命令提示符中运行以下命令:
dart run build_runner build
这将基于注解的类生成所有文件。
Models
任何带有@Model
注解的类_Class
都会生成四个新类:ClassData
、Class
、ClassDependency
和ClassEntity
。
@Model(name: 'class', as: #classes)
abstract class _Class {
@Field(name: 'name')
String? get name;
@Field(name: 'timestamp')
DateTime get timestamp;
@ForeignField(name: 'school-id', referTo: _School)
String get schoolId;
}
Data
ClassData
仅包含带有@Field
、@PolymorphicField
和@ModelField
注解的getter。
@JsonSerializable(anyMap: true, explicitToJson: true)
class ClassData {
@JsonKey(name: 'name')
final String? name;
@JsonKey(name: 'timestamp', required: true, disallowNullValue: true)
final DateTime timestamp;
factory ClassData.fromJson(Map json) => _$ClassDataFromJson(json);
const ClassData({
required this.name,
required this.timestamp,
});
Map<String, Object?> toJson() => _$ClassDataToJson(this);
}
Model
Class
扩展自ClassData
,实现_Class
,并额外包含一个id
字段,只包含带有@ForeignField
和@QueryField
注解的getter。
@JsonSerializable(anyMap: true, explicitToJson: true)
class Class extends ClassData implements _Class {
@JsonKey(name: '_id', required: true, disallowNullValue: true)
final String id;
@JsonKey(name: 'school-id', required: true, disallowNullValue: true)
final String schoolId;
factory Class.fromJson(String id, Map json) =>
_$ClassFromJson({...json, '_id': id});
const Class({
required this.id,
required this.schoolId,
required super.name,
required super.timestamp,
});
Map<String, Object?> toJson() =>
_$ClassToJson(this)
..remove('_id');
}
dORM Components
ClassDependency
和ClassEntity
分别扩展自Dependency<ClassData>
和Entity<ClassData, Class>
,由dorm_framework
包导出。
Accessors
代码生成还会创建一个名为Dorm
的新类,其中包含存储库访问器。在上述示例中定义为:
class Dorm {
final BaseEngine _engine;
const Dorm(this._engine);
DatabaseEntity<ClassData, Class> get classes =>
DatabaseEntity(const ClassEntity(), engine: _engine);
}
有关如何获取Engine
的更多信息,请参阅dorm_*_database
包。通过Dorm
实例,可以使用Repository
操作类,Repository
也由dorm_framework
导出:
void main() async {
final Dorm dorm /* = ... */;
// 创建
final Class c = await dorm.classes.repository.put(
ClassDependency(schoolId: 'school-0'),
ClassData(name: 'A class.', timestamp: DateTime.now()),
);
// 读取
final Future<Class> fc = await dorm.classes.repository.peek('class-1');
final Future<List<Class>> fcs = await dorm.classes.repository.peekAll();
final Stream<Class> sc = dorm.classes.repository.pull('class-1');
final Stream<List<Class>> scs = dorm.classes.repository.pullAll();
// 更新
final Class uc = await dorm.classes.repository.push(Class(
id: 'class-1',
schoolId: 'school-1',
name: 'A new class.',
timestamp: DateTime.now(),
));
// 删除
await dorm.classes.repository.pop('class-1');
}
Polymorphism
考虑以下注解代码:
abstract class _Action {}
@PolymorphicData(name: 'attack')
abstract class _Attack implements _Action {
@Field(name: 'strength')
int get strength;
}
@PolymorphicData(name: 'defence')
abstract class _Defense implements _Action {
@Field(name: 'resistence')
int get resistence;
}
@PolymorphicData(name: 'healing', as: #heal)
abstract class _Healing implements _Action {
@Field(name: 'health')
int get health;
}
@Model(name: 'operation', as: #operations)
abstract class _Operation {
@Field(name: 'name')
String get name;
@PolymorphicField(name: 'action', pivotName: 'type', pivotAs: #type)
_Action get action;
}
生成的代码将包含一个名为Action
的抽象类及其三个子类:Attack
、Defense
和Healing
。它还将包含一个名为ActionType
的枚举,有三个值:attack
、defense
和heal
(不是healing
;查看其PolymorphicData
的as
参数)。
_Operation
模型将按上述方式生成,但会额外包含一个名为type
的字段,类型为ActionType
,这将允许用户检查action
字段的运行时类型。
以下代码演示了如何操作带有@PolymorphicField
注解的Model
字段:
void main() async {
final Operation o1 = await dorm.operations.repository.put(
const OperationDependency(),
OperationData(name: 'AoT', action: Attack(strength: 42), type: ActionType.attack),
);
final Operation o2 = await dorm.operations.repository.peek('543f2f8da023');
final int value;
switch (operation.type) {
case ActionType.attack:
final Attack attack = operation.action as Attack;
value = attack.strength;
break;
case ActionType.defense:
final Defense defense = operation.action as Defense;
value = defense.resistence;
break;
case ActionType.heal:
final Healing healing = operation.action as Healing;
value = healing.health;
break;
}
}
Unique Identification
Simple
如果:
@Model(name: 'country', as: #countries, uidType: UidType.simple())
abstract class _Country {
@Field(name: 'name')
String get name;
}
那么:
void main() async {
final Country country = await dorm.countries.repository.put(
CountryDependency(),
CountryData(name: 'Brazil'),
);
// uuid
assert(country.id == '27f04af67a1f');
}
Composite
如果:
@Model(name: 'state', as: #states, uidType: UidType.composite())
abstract class _State {
@Field(name: 'name')
String get name;
@ForeignField(name: 'country-id', referTo: _Country)
String get countryId;
}
那么:
void main() async {
final State state = await dorm.states.repository.put(
StateDependency(countryId: '27f04af67a1f'),
StateData(name: 'Rio de Janeiro'),
);
// ${countryId}_uuid
assert(country.id == '27f04af67a1f_367f1672f637');
}
Same-as
如果:
@Model(name: 'capital', as: #capitals, uidType: UidType.sameAs(_Country))
abstract class _Capital {
@Field(name: 'name')
String get name;
@ForeignField(name: 'country-id', referTo: _Country)
String get countryId;
}
那么:
void main() async {
final Capital capital = await dorm.capitals.repository.put(
CapitalDependency(countryId: '27f04af67a1f'),
CapitalData(name: 'Brasilia'),
);
// countryId
assert(capital.id == '27f04af67a1f');
}
Custom
如果:
CustomUidValue _identifyCitizen(Object data) {
data as _Citizen;
if (data.isForeigner) {
return CustomUidValue.value(data.visaCode!);
}
if (data.socialSecurity != null) {
return CustomUidValue.value(data.socialSecurity);
}
return const CustomUidValue.simple();
}
@Model(name: 'citizen', as: #citizens, uidType: UidType.custom(_identifyCitizen))
abstract class _Citizen {
@Field(name: 'name')
String get name;
@Field(name: 'is-foreigner', defaultValue: false)
bool get isForeigner;
@Field(name: 'visa-code')
String? get visaCode;
@Field(name: 'ssn')
String? get socialSecurity;
@ForeignField(name: 'country-id', referTo: _Country)
String get countryId;
}
那么:
void main() async {
final Citizen c1 = await dorm.citizens.repository.put(
CitizenDependency(countryId: '27f04af67a1f'),
CitizenData(
name: 'Rodrigo Maia',
isForeigner: true,
visaCode: '4bb6',
socialSecurity: '11111111111',
),
);
// visaCode
assert(c1.id == '4bb6');
final Citizen c2 = await dorm.citizens.repository.put(
CitizenDependency(countryId: '27f04af67a1f'),
CitizenData(
name: 'Arthur Lira',
isForeigner: false,
visaCode: null,
socialSecurity: '22222222222',
),
);
// socialSecurity
assert(c2.id == '22222222222');
final Citizen c3 = await dorm.citizens.repository.put(
CitizenDependency(countryId: '27f04af67a1f'),
CitizenData(name: 'Capivara Filó', isForeigner: false, visaCode: null, socialSecurity: null),
);
// uuid
assert(c3.id == 'b2a6304807a0');
}
更多关于Flutter代码生成插件dorm_generator的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter代码生成插件dorm_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
dorm_generator
是一个用于 Flutter 的代码生成插件,它可以帮助开发者自动生成与数据库相关的代码,特别是与 dorm
库一起使用时。dorm
是一个轻量级的 ORM(对象关系映射)库,用于在 Flutter 应用中简化数据库操作。
使用 dorm_generator
的步骤
-
添加依赖
首先,你需要在pubspec.yaml
文件中添加dorm
和dorm_generator
的依赖。dependencies: flutter: sdk: flutter dorm: ^0.1.0 # 请使用最新版本 dev_dependencies: build_runner: ^2.1.0 # 用于代码生成 dorm_generator: ^0.1.0 # 请使用最新版本
-
定义数据模型
创建一个 Dart 类来表示你的数据模型,并使用[@Entity](/user/Entity)
注解标记它。dorm_generator
会根据这个类生成相应的数据库操作代码。import 'package:dorm/dorm.dart'; [@Entity](/user/Entity)() class User { @PrimaryKey() int id; String name; int age; User({this.id, this.name, this.age}); }
-
生成代码
运行build_runner
来生成代码。你可以在终端中运行以下命令:flutter pub run build_runner build
这将会生成与
User
类相关的数据库操作代码。 -
使用生成的代码
生成的代码通常包括一个UserDao
类,你可以使用它来执行数据库操作。import 'package:dorm/dorm.dart'; import 'user.g.dart'; // 生成的代码 void main() async { final db = await openDatabase('my_database.db'); final userDao = UserDao(db); // 插入用户 final user = User(id: 1, name: 'John Doe', age: 30); await userDao.insert(user); // 查询用户 final users = await userDao.findAll(); print(users); }