Flutter代码生成插件dorm_generator的使用

dorm_generator

pub package
pub popularity
pub likes
pub points

提供了与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都会生成四个新类:ClassDataClassClassDependencyClassEntity

@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

ClassDependencyClassEntity分别扩展自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的抽象类及其三个子类:AttackDefenseHealing。它还将包含一个名为ActionType的枚举,有三个值:attackdefenseheal(不是healing;查看其PolymorphicDataas参数)。

_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

1 回复

更多关于Flutter代码生成插件dorm_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


dorm_generator 是一个用于 Flutter 的代码生成插件,它可以帮助开发者自动生成与数据库相关的代码,特别是与 dorm 库一起使用时。dorm 是一个轻量级的 ORM(对象关系映射)库,用于在 Flutter 应用中简化数据库操作。

使用 dorm_generator 的步骤

  1. 添加依赖
    首先,你需要在 pubspec.yaml 文件中添加 dormdorm_generator 的依赖。

    dependencies:
      flutter:
        sdk: flutter
      dorm: ^0.1.0  # 请使用最新版本
    
    dev_dependencies:
      build_runner: ^2.1.0  # 用于代码生成
      dorm_generator: ^0.1.0  # 请使用最新版本
    
  2. 定义数据模型
    创建一个 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});
    }
    
  3. 生成代码
    运行 build_runner 来生成代码。你可以在终端中运行以下命令:

    flutter pub run build_runner build
    

    这将会生成与 User 类相关的数据库操作代码。

  4. 使用生成的代码
    生成的代码通常包括一个 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);
    }
回到顶部