侧边栏壁纸
博主头像
DOKI SEKAI博主等级

行动起来,活在当下

  • 累计撰写 114 篇文章
  • 累计创建 38 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

在 Flutter 项目中引入并使用 ObjectBox

君
2024-11-19 / 0 评论 / 1 点赞 / 63 阅读 / 8324 字

**在 Flutter 项目中引入并使用 ObjectBox **

ObjectBox 是一个高性能的 NoSQL 数据库,专为嵌入式场景(如移动端和桌面应用)设计,具有高效的增删查改能力,适合需要本地数据存储的 Flutter 项目。


1. 环境准备

1.1 安装依赖

pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  objectbox: ^1.7.0
  objectbox_flutter_libs: ^1.7.0 # 针对移动平台使用的库

dev_dependencies:
  build_runner: ^2.4.6       # 用于代码生成
  objectbox_generator: ^1.7.0

运行以下命令安装依赖:

flutter pub get

2. 创建实体类

使用 @Entity() 注解定义需要存储的数据模型。每个实体类必须有一个 int 类型的 ID 字段,并且不能是 final,以便 ObjectBox 能自动生成或管理主键。

示例:用户实体类

import 'package:objectbox/objectbox.dart';

@Entity()
class User {
  int id = 0; // 主键,由 ObjectBox 自动生成

  final String username;
  final String passwordHash;
  final String? phone;
  final String? email;
  final String? avatarUrl;

  @Property(type: PropertyType.date) // 指定日期存储精度为毫秒
  final DateTime createdAt;

  @Property(type: PropertyType.date) // 指定日期存储精度为毫秒
  final DateTime updatedAt;

  User({
    required this.username,
    required this.passwordHash,
    this.phone,
    this.email,
    this.avatarUrl,
    required this.createdAt,
    required this.updatedAt,
  });
}

3. 生成代码

ObjectBox 使用 build_runner 工具自动生成数据交互代码。生成的文件会包含实体类的元信息和增删查改的操作逻辑。

在项目根目录运行以下命令:

dart run build_runner build

生成的文件通常为:

  • objectbox.g.dart:主数据库交互文件。

如果需要清理构建缓存,可以运行:

dart run build_runner clean

4. 初始化 ObjectBox

在应用启动时,需要初始化 ObjectBox 数据库。

步骤:

  1. 使用 getApplicationDocumentsDirectory() 获取存储路径。
  2. 调用 openStore() 方法初始化数据库。

代码示例:

import 'package:flutter/material.dart';
import 'package:objectbox/objectbox.dart';
import 'package:path_provider/path_provider.dart';

late final Store store; // 全局数据库实例

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 获取存储目录并初始化 ObjectBox
  final directory = await getApplicationDocumentsDirectory();
  store = await openStore(directory: directory.path);

  runApp(MyApp());
}

5. 数据操作

ObjectBox 提供了一组简单高效的操作方法,包括增、删、查、改。以下是详细示例:

5.1 插入数据

通过 Box 对象的 put() 方法插入或更新数据。

final user = User(
  username: 'JohnDoe',
  passwordHash: 'hashed_password',
  phone: '123456789',
  email: '[email protected]',
  avatarUrl: 'https://example.com/avatar.png',
  createdAt: DateTime.now(),
  updatedAt: DateTime.now(),
);

final box = store.box<User>();
box.put(user); // 插入或更新数据

5.2 查询数据

查询所有数据

使用 getAll() 方法获取所有实体:

final box = store.box<User>();
final users = box.getAll(); // 获取所有用户
for (var user in users) {
  print('User: ${user.username}, Created At: ${user.createdAt}');
}

条件查询

通过 query() 方法创建查询语句:

final query = box.query(User_.username.equals('JohnDoe')).build();
final results = query.find(); // 查询结果
query.close(); // 查询完成后释放资源

分页查询

通过 offsetlimit 分页加载:

final results = box.query().build().find(limit: 10, offset: 20);

5.3 更新数据

通过 put() 方法更新数据:

final user = box.get(1); // 获取 ID 为 1 的用户
if (user != null) {
  user.email = '[email protected]';
  box.put(user); // 更新数据
}

5.4 删除数据

根据 ID 删除

box.remove(1); // 删除 ID 为 1 的用户

删除所有数据

box.removeAll(); // 删除所有用户

6. 关系型数据

ObjectBox 支持一对一、一对多、多对多的关系存储。

一对多关系示例

@Entity()
class Author {
  int id = 0;
  String name;

  @Backlink('author') // 反向关系
  final books = ToMany<Book>();

  Author({required this.name});
}

@Entity()
class Book {
  int id = 0;
  String title;

  final author = ToOne<Author>(); // 引用 Author

  Book({required this.title});
}

插入和查询:

final author = Author(name: 'Author Name');
final book1 = Book(title: 'Book One')..author.target = author;
final book2 = Book(title: 'Book Two')..author.target = author;

final authorBox = store.box<Author>();
final bookBox = store.box<Book>();

authorBox.put(author); // 插入作者
bookBox.putMany([book1, book2]); // 插入书籍

// 查询作者的书籍
final retrievedAuthor = authorBox.get(author.id)!;
print(retrievedAuthor.books.map((book) => book.title).toList());

7. 数据持久化和安全性

  • ObjectBox 默认将数据存储在应用的私有目录中,路径由 path_provider 提供,其他应用无法访问。
  • 关机或断电数据安全性:ObjectBox 使用事务机制,确保所有写入操作是原子性的,即使发生崩溃或断电,数据仍然一致。
  • 加密支持:可以手动对敏感数据字段进行加密,例如使用 encrypt 包。

8. 清理资源

为了避免资源泄露,在不需要时可以关闭数据库:

store.close();

9. 常见问题

9.1 运行 build_runner 报错

  • 确保 pubspec.yaml 中正确添加了 build_runnerobjectbox_generator
  • 运行以下命令清理构建缓存:
    dart run build_runner clean
    dart run build_runner build
    

9.2 时间字段警告

如果使用 DateTime 字段,请明确指定存储类型为 @Property(type: PropertyType.date)


10. 适用场景

  • 本地消息存储(如聊天应用)。
  • 离线优先的业务逻辑(如电商订单缓存)。
  • 快速的数据查询和处理(如联系人管理)。

1

评论区