Flutter Firestore数据转换插件firestore_converter的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter Firestore数据转换插件firestore_converter的使用

介绍

firestore_converter 是一个用于简化 Firestore 数据模型与 Dart 类之间转换的插件。通过使用 [@FirestoreConverter](/user/FirestoreConverter) 注解,可以自动生成 withConverter 实现,从而减少样板代码。它最好与其他注解库(如 freezedjson_serializable)一起使用,但并不是必需的。

减少样板代码

Before:

part 'example.freezed.dart';
part 'example.g.dart';

[@freezed](/user/freezed)
class Example<T> with _$Example<T> {
  factory Example(int a) = _Example;
  factory Example.fromJson(Map<String, Object?> json) => _$ExampleFromJson(json);
}

CollectionReference<Example> exampleCollection([String path = 'examples']) {
  return FirebaseFirestore.instance
      .collection(path)
      .withConverter<Example>(
        fromFirestore: (snapshot, _) => Example.fromJson(snapshot.data()!),
        toFirestore: (instance, _) => instance.toJson(),
      );
}

DocumentReference<Example> exampleDoc({String path = 'examples', required String docId}) {
  return FirebaseFirestore.instance
      .doc('$path/$docId')
      .withConverter<Example>(
        fromFirestore: (snapshot, _) => Example.fromJson(snapshot.data()!),
        toFirestore: (instance, _) => instance.toJson(),
      );
}

After:

part 'example.firestore_converter.dart';
part 'example.freezed.dart';
part 'example.g.dart';

[@freezed](/user/freezed)
[@FirestoreConverter](/user/FirestoreConverter)(defaultPath: 'examples')
class Example<T> with _$Example<T> {
  factory Example(int a) = _Example;
  factory Example.fromJson(Map<String, Object?> json) => _$ExampleFromJson(json);
}

安装

  1. 安装 build_runner 以运行代码生成:

    flutter pub add dev:build_runner
    
  2. 安装 firestore_converter_generator 作为开发依赖:

    flutter pub add dev:firestore_converter_generator
    
  3. 安装 firestore_converter 作为普通依赖:

    flutter pub add firestore_converter
    

升级指南(适用于版本1.0.8之前的用户)

如果你之前使用的是 firestore_converter 版本1.0.8之前的版本,请按照以下步骤进行升级:

  1. 移除旧的依赖:

    flutter pub remove firestore_converter_annotation
    flutter pub remove firestore_converter
    
  2. 添加新的依赖:

    flutter pub add dev:build_runner
    flutter pub add dev:firestore_converter_generator
    flutter pub add firestore_converter
    
  3. 在源代码中替换导入语句:

    • import 'package:firestore_converter_annotation/firestore_converter_annotation.dart'; 替换为:
      import 'package:firestore_converter/firestore_converter.dart';
      

使用方法

在数据类上使用 [@FirestoreConverter](/user/FirestoreConverter)(defaultPath: 'someDataPathInFirestore') 注解,将生成两个辅助函数:

  • ${modelClassName}Collection
  • ${modelClassName}Doc

请注意,这些是函数而不是成员,因为目前无法通过代码生成向模型类添加静态函数。模型名称的首字母将被转换为小写,以符合 Dart 的函数命名规范。

实现 fromJsontoJson

firestore_converter 依赖于 fromJsontoJson 方法的存在或实现。你可以使用 freezedjson_serializable 或其他注解库来方便地实现这两个方法。当然,你也可以手动实现它们,但这可能会违背使用代码生成的目的。

注意事项

  • 必须启用或实现 JSON 转换的 fromJsontoJson 方法。
  • 使用给定的路径作为集合和文档的默认参数。
  • 不支持 build.yaml 中的默认设置,因为路径设置是针对每个模型类的。

示例:使用 firestore_converterfreezed

定义你的模型类,例如 example.dart

part 'example.firestore_converter.dart';
part 'example.freezed.dart';
part 'example.g.dart';

[@freezed](/user/freezed)
[@FirestoreConverter](/user/FirestoreConverter)(defaultPath: 'examples')
class Example<T> with _$Example<T> {
  factory Example(int a) = _Example;
  factory Example.fromJson(Map<String, Object?> json) => _$ExampleFromJson(json);
}

运行代码生成以生成 example.firestore_converter.dart

flutter pub run build_runner build --delete-conflicting-outputs

开始使用:

// 现在可以轻松创建完全类型的 CollectionReferences、DocumentReferences 或 SnapShot 对象:
CollectionReference<Example> col1 = exampleCollection().orderBy('date', descending: true); // 默认路径为注解中的 'examples'
CollectionReference<Example> col2 = exampleCollection('some_other_path').orderBy('a', descending: true);
DocumentReference<Example> doc1 = exampleDoc(docId: 'exampleId'); // 默认路径为注解中的 'examples'
DocumentReference<Example> doc2 = exampleDoc(path: 'some_other_path', docId: 'exampleId');

// 检索某些文档数据
var myDoc = exampleDoc(path: 'some_other_path', docId: 'exampleId').get();
// 直接从快照访问类型化的成员
debugPrint(myDoc.data().a);

完整示例 Demo

以下是一个完整的示例,展示了如何使用 firestore_converterfreezed 来创建一个简单的 Flutter 应用程序,该应用程序连接到 Firestore 并显示用户列表:

// 这个示例需要 Firestore 模拟器正在运行!
// 通过以下命令启动:
// firebase emulators:start --project demo-example

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:faker/faker.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
import 'package:firestore_converter/firestore_converter.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'main.firestore_converter.dart';
part 'main.freezed.dart';
part 'main.g.dart';

var faker = Faker();

[@FirestoreConverter](/user/FirestoreConverter)(defaultPath: 'users')
[@freezed](/user/freezed)
class User with _$User {
  factory User({
    required String name,
    required String email,
    required int salary,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 这个示例需要 Firestore 模拟器正在运行!
  // 通过以下命令启动:
  // firebase emulators:start --project demo-example

  await Firebase.initializeApp(
    options: const FirebaseOptions(
      apiKey: 'not-required-for-emulator',
      appId: 'not-required-for-emulator',
      messagingSenderId: 'not-required-for-emulator',
      projectId: 'demo-example',
    ),
  );

  try {
    FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
  } catch (e) {
    print(e);
    rethrow;
  }

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: Builder(builder: (context) {
          return FloatingActionButton(
            key: const Key('addButton'),
            onPressed: () async {
              var newUser = User(
                email: faker.internet.email(),
                name: faker.person.name(),
                salary: faker.randomGenerator.integer(100000),
              );
              try {
                await userCollection().add(newUser);
                ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                  content: Text('New user added'),
                  key: Key('snackbar'),
                ));
              } catch (e) {
                debugPrint(e.toString());
                rethrow;
              }
            },
            child: const Icon(Icons.add),
          );
        }),
        body: FirestoreListView<User>(
          query: userCollection().orderBy('name'),
          itemBuilder: (context, snapshot) => Card(
            child: ListTile(
              key: Key(snapshot.data().name),
              title: Text(snapshot.data().name),
              subtitle: Row(
                children: [
                  Text(snapshot.data().email),
                  const Expanded(child: Center()),
                  Text(snapshot.data().salary.toString()),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

更多关于Flutter Firestore数据转换插件firestore_converter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Firestore数据转换插件firestore_converter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 firestore_converter 插件在 Flutter 中进行 Firestore 数据转换的示例代码。firestore_converter 插件允许你将 Firestore 数据与 Dart 模型之间进行无缝转换,特别是当你使用 freezedjson_serializable 生成的 Dart 模型时。

首先,确保你的 pubspec.yaml 文件中包含以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  cloud_firestore: ^3.1.0
  firestore_converter: ^0.4.0+2  # 请检查最新版本号
  json_annotation: ^4.0.1  # 如果你使用 json_serializable

然后,运行 flutter pub get 来获取这些依赖项。

示例模型

假设你有一个简单的用户模型 User,使用 json_serializable 来生成 fromJsontoJson 方法:

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final String id;
  final String name;
  final int age;

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

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

生成 user.g.dart 文件:

flutter pub run build_runner build

使用 Firestore 和 firestore_converter

接下来,在你的 Flutter 应用中使用 firestore_converter 将 Firestore 数据转换为 User 对象。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firestore_converter/firestore_converter.dart';
import 'user.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化 Firestore 实例
  final Firestore firestore = Firestore.instance;

  // 注册 User 模型的转换器
  FirestoreConverter.useConverters = true;
  FirestoreConverter.registerFromDocument<User>((snapshot, options) => User.fromJson(snapshot.data()! as Map<String, dynamic>));
  FirestoreConverter.registerToDocument<User>((user) => user.toJson());

  // 添加一个示例用户到 Firestore
  await firestore.collection('users').add(<String, dynamic>{
    'name': 'Alice',
    'age': 30,
  });

  // 从 Firestore 读取用户数据
  final QuerySnapshot<Map<String, dynamic>> snapshot = await firestore.collection('users').get();
  final List<User> users = snapshot.docs.map((doc) => User.fromJson(doc.data()! as Map<String, dynamic>)).toList();

  // 输出用户数据
  users.forEach((user) => print('User: ${user.name}, Age: ${user.age}'));
}

注意:在上面的代码中,我们手动将 Firestore 数据转换为 User 对象。然而,通过使用 firestore_converter 的注册功能,我们可以让 Firestore 自动处理这些转换。但由于 firestore_converter 插件的 API 可能在不同版本中有所不同,这里我们手动展示了转换过程。实际上,如果插件支持,你可以利用插件的自动转换功能来简化代码。

为了利用 firestore_converter 的自动转换功能(如果支持),你可能需要调整代码以使用插件提供的封装方法,但具体实现依赖于插件的当前版本和 API。由于 firestore_converter 的 API 可能会变化,请参考其官方文档和示例以获取最新和最准确的用法。

希望这能帮助你理解如何在 Flutter 中使用 firestore_converter 插件进行 Firestore 数据转换!

回到顶部