Flutter对象关系映射插件flora_orm的使用
Flutter对象关系映射插件flora_orm的使用
flora_orm
为Flutter提供的数据库ORM(对象关系映射)。
该ORM支持:
- shared_preferences - 所有平台
- sqflite - iOS/Android/MacOS
- sqflite_common_ffi - 磁盘上 - iOS/Android/MacOS/Linux/Windows
- sqflite_common_ffi - 内存中 - iOS/Android/MacOS/Linux/Windows
获取开始
要开始使用,你需要在项目中添加 flora_orm
。请遵循以下步骤:
- 在项目的根目录打开终端。你可以在Android Studio中通过按
Alt+F12
或在VS Code中按Ctrl+
来做到这一点。 - 运行以下命令:
flutter pub add flora_orm
这条命令会在你的包的 pubspec.yaml
文件中添加一行,并运行一个隐式的 flutter pub get
。添加的行将如下所示:
dependencies:
flora_orm:
使用示例
导入 flora_orm.dart
:
import 'package:flora_orm/flora_orm.dart';
初始化
要使用 flora_orm
,你需要创建实体类。
对于VS Code用户,我们为你提供了一个代码片段,这样你就不用再手动输入样板代码了。 有关如何添加和使用代码片段的更多信息,请参阅此处。
你的实体类必须满足以下条件:
- 命名约定是
{entity_name}.entity.dart
。例如user.entity.dart
(推荐)。 - 你必须在实体文件的顶部添加两个
part
:{entity_name}.entity.g.dart
和{entity_name}.entity.migrations.dart
。 - 你必须用
@entity
(或@OrmEntity()
用于细粒度控制)来注解类。 - 你的实体类必须扩展
Entity<{YourEntityName}, {YourEntityName}Meta> with _{YourEntityName}Mixin, {YourEntityName}Migrations
。
示例实体
import 'package:flora_orm/flora_orm.dart';
part 'user.entity.g.dart';
part 'user.entity.migrations.dart';
@OrmEntity(tableName: 'user')
class UserEntity extends Entity<UserEntity, UserEntityMeta>
with _UserEntityMixin, UserEntityMigrations {
const UserEntity({
super.id,
super.collectionId,
super.createdAt,
super.updatedAt,
this.claims,
this.uid,
this.email,
this.phoneNumber,
this.displayName,
this.photoURL,
this.provider,
});
[@override](/user/override)
@column
final List<String>? claims;
[@override](/user/override)
@column
final String? uid;
[@override](/user/override)
@column
final String? email;
[@override](/user/override)
@column
final String? phoneNumber;
[@override](/user/override)
@column
final String? displayName;
[@override](/user/override)
@OrmColumn(isEnum: true)
final OAuthProvider? provider;
[@override](/user/override)
@column
final String? photoURL;
}
enum OAuthProvider { google, apple, facebook }
一旦你创建或更新了实体文件,打开终端并从项目的根目录运行以下命令:
dart run build_runner build
OrmManager
你需要一个 OrmManager
的实例来与存储进行交互。
尽早创建 OrmManager
的实例。
我们建议在应用程序启动时使用 get_it
或任何你喜欢的DI框架将其注册为单例。
例如,在 void main()
函数中,在 runApp()
之前,你可以有以下内容:
final ormManager = OrmManager(
/// 每次添加或更新实体时(如添加新属性/字段),请更新此版本号
dbVersion: 1,
/// 如果未指定,dbEngine 默认为 DbEngine.sqflite
dbEngine: DbEngine.sqflite,
dbName: 'your_db_name_here.db',
tables: <Entity>[
/// 实例化所有你希望保存在数据库中的实体
const UserEntity(),
],
);
GetIt.I.registerSingleton(ormManager);
为了保持代码整洁,我们建议你将上述代码放在单独的文件中。例如在 src/orm.init.dart
中。
重要提示:在添加实体类(并更新现有实体类)后,请不要忘记:
- 从终端运行:
dart run build_runner build
- 更新
OrmManager
中的dbVersion
- 如果你更改了列或添加了新的实体类。 - 注册任何新的实体到
OrmManager
的tables: []
中。
dbEngine
的值默认为 DbEngine.sqflite
,可以是以下之一:
inMemory,
sqfliteCommon,
sqflite,
sharedPreferences,
然而,并不是所有的引擎都适用于所有的平台。下面是每个平台及其支持的引擎的详细情况:
如果你提供了平台不支持的 dbEngine
值,则会使用该平台的默认值。
Android: all (我们推荐 sqflite)
iOS: all (我们推荐 sqflite)
macOS: all (我们推荐 sqflite)
Linux: inMemory, sqfliteCommon, sharedPreferences (默认为 sqfliteCommon)
Windows: inMemory, sqfliteCommon, sharedPreferences (默认为 sqfliteCommon)
web: sharedPreferences (默认为 sharedPreferences)
一旦你的 OrmManager
设置好,你就可以在代码的任何地方使用它。如果你使用的是 get_it
,你可以像这样获取你的 storage
实例:
final orm = GetIt.I<OrmManager>();
final {EntityType}Orm storage = orm.getStorage(/* 实体实例 */);
例如,要获取 UserEntity
的 storage
:
final orm = GetIt.I<OrmManager>();
final UserEntityOrm storage = orm.getStorage(const UserEntity())
重要提示:你 需要 指定类型(如上面的 UserEntityOrm
)以便稍后在 Filter
中获取 ColumnDefition
。类型类是在你运行 dart run build_runner build
时自动生成的。
CRUD操作
CRUD - 创建
如果记录具有相同的 id
,将会抛出错误:
final entity = await storage.insert(
UserEntity(id: 'user1',
displayName: 'Test User',
));
我们建议使用 uuid
生成器来生成 id
。
你可以使用 insertOrUpdate
代替,这将在记录存在时更新记录:
final entity = await storage.insertOrUpdate(
UserEntity(id: 'user1',
displayName: 'Test User',
));
你可以一次插入多条记录:
final entities = await storage.insertList([
UserEntity(id: 'user1',
displayName: 'Test User'),
...,
]);
有一个等效于 insertOrUpdate
的方法可以处理多条记录:
final entities = await storage.insertOrUpdateList([
UserEntity(id: 'user1',
displayName: 'Test User'),
...,
]);
CRUD - 读取
获取单个记录:
final entity = await storage.firstWhereOrNull(...);
获取多个记录:
final entities = await storage.where(...);
CRUD - 更新
你可以使用前面解释过的 insertOrUpdate
选项,这将在记录不存在时插入记录。但是,如果你只想严格更新现有的记录,那么:
final updatedCount = await storage.update(where: ...);
CRUD - 删除
final deletedCount = await storage.delete(where: ...);
Filter
函数
大多数查询都需要一个 where
参数,这是一个必须返回 Filter
的函数。
该函数有一个参数 t
,它是你的属性作为 ColumnDefinition
的元描述。
以下是几个示例:
获取 UserEntity
,其 id
为 'user1'
final user = await storage.firstWhereOrNull(
where: (t) => Filter(
t.id,
value: 'user1',
),
);
删除所有 UserEntity
,其 uid
不为 null
await storage.delete(
where: (t) => Filter(
t.uid,
condition: OrmCondition.notNull,
),
);
获取所有 UserEntity
,其 rating
大于等于 20
final users = await storage.where(
where: (t) => Filter(
t.rating,
condition: OrmCondition.greaterThanOrEqual,
value: 20,
),
);
获取所有 UserEntity
,其 rating
在 10 到 100 之间
final users = await storage.where(
where: (t) => Filter(
t.rating,
condition: OrmCondition.between,
value: 10,
secondaryValue: 100,
),
);
链接和分组过滤器
你可以拥有复杂的过滤器以满足你的需求。
使用诸如 startGroup()
、endGroup()
、filter()
、and()
和 or()
等实用函数。
filter()
、and()
和 or()
也有 openGroup
和 closeGroup
参数,以简化分组,因此你可能不需要 startGroup()
和 endGroup()
。然而,我们建议使用 startGroup()
和 endGroup()
,因为它们易于阅读和理解其效果。
想想分组就像打开和关闭括号,并将操作放在 <openGroup>
…<closeGroup>
之间的括号内。
在下面的例子中,最后一个 or()
和 and()
过滤器将被分组到 (...)
中。
final users = await storage.where(
where: (t) => Filter.startGroup()
.filter(
t.displayName,
condition: OrmCondition.like,
value: '%flu%',
)
.and(
t.rating,
value: 10,
)
.endGroup()
.or(
openGroup: true,
t.displayName,
value: 'Loveable',
)
.and(
t.rating,
value: 11002,
closeGroup: true,
),
);
startGroup()
通常需要跟随 filter()
之后才能链接其他过滤器。记得 endGroup()
/closeGroup
。
迁移 - 对实体类和数据库更新的更改
如果你更新了任何 Entity
类,你需要再次运行 dart run build_runner build
。
如果你在 Entity
类中添加/删除了 @column
或任何注解项,那么 增加 OrmManager
的 dbVersion
,注册 新的 Entity
类到 OrmManager
的 tables: []
中,并在相应的 {entity_name}.entity.migrations.dart
文件中添加迁移。
最简单的迁移方式是删除并重新创建实体表(丢失该表中的所有数据),或者指定新增的列:
示例 UserEntity
迁移(第一次运行 dart run build_runner build
时自动生成该文件)
mixin UserEntityMigrations on Entity<UserEntity, UserEntityMeta> {
[@override](/user/override)
bool recreateTableAt(int newVersion) {
return switch (newVersion) {
/// 当 dbVersion = 3 时,删除并重新创建表
3 => true,
_ => false,
};
}
[@override](/user/override)
List<ColumnDefinition> addColumnsAt(int newVersion) {
return switch (newVersion) {
/// 这里我们说我们在设置 dbVersion = 2 时添加了名为 provider 的属性。
/// 在你的实体类中的所有 [@column] 属性都可以作为 [ColumnDefinition] 在 [meta] 对象中访问
2 => [meta.provider],
_ => [],
};
}
}
在 {entity_name}.entity.migrations.dart
中,你还可以覆盖 downgradeTable()
和 additionalUpgradeQueries()
,返回在该操作期间必须执行的查询。
你还可以覆盖 onUpgradeComplete
和 onDowngradeComplete
以返回在升级/降级完成后的自定义查询。
还有一个 onCreateComplete
,你可以在其中返回首次创建数据库时必须执行的查询。
重要提示:作为提醒,在添加实体类(并编辑现有实体类)后,请不要忘记:
- 从终端运行:
dart run build_runner build
- 更新
OrmManager
中的dbVersion
- 如果你更改了列或添加了新的实体类。 - 注册新的实体到
OrmManager
的tables: []
中。
支持的数据类型
- String
- bool
- int
- double
- DateTime
- 枚举(需要指定
@OrmColumn(isEnum: true)
) - 自定义类(对象) - 它们需要有工厂构造函数
fromMap(map)
和函数toMap()
- 上述类型的列表(例如
List<String>
)
所有实体类已经实现了 toMap
。如果你想让类作为另一个实体的列,你需要定义工厂构造函数 fromMap(map)
。
为了方便起见,你可以调用 load()
函数,它会处理其余部分。
UserEntity
的示例工厂构造函数:
@OrmEntity(tableName: 'user')
class UserEntity extends Entity<UserEntity, UserEntityMeta> {
/// 默认构造函数在这里
factory UserEntity.fromMap(map) {
return const UserEntity().load(map);
}
/// 其余类在这里
}
完整示例代码
import 'package:example/user.entity.dart';
import 'package:flora_orm/flora_orm.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/// 我们推荐你实例化并注册 OrmManager 为单例
final orm = OrmManager(
dbVersion: 1,
dbName: 'orm_db_test.db',
tables: <Entity>[
/// 你必须在此处注册所有你要保存的实体
UserEntity(),
],
);
/// 获取你想要使用的实体类型的存储实例。
/// **重要** 记得指定类型 ([UserEntityOrm] 用于此示例)
/// 以便在使用存储对象时使生活更轻松
late final UserEntityOrm storage = orm.getStorage(UserEntity());
Future<UserEntity> _insertUser() async {
await storage.insertOrUpdate(
UserEntity(
id: 'user1',
firstName: 'John',
lastName: 'Doe',
),
);
final user = await storage.firstWhereOrNull(
(t) => Filter(t.lastName, value: 'Doe'),
);
return user!;
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: FutureBuilder(
future: _insertUser(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Text('Loading...');
}
final user = snapshot.data!;
return Text('Hello, ${user.firstName} ${user.lastName}');
},
),
),
);
}
}
更多关于Flutter对象关系映射插件flora_orm的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter对象关系映射插件flora_orm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用flora_orm
对象关系映射(ORM)插件的示例代码。flora_orm
插件允许你以声明性的方式定义数据模型,并轻松地在Flutter应用中执行数据库操作。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加flora_orm
依赖:
dependencies:
flutter:
sdk: flutter
flora_orm: ^最新版本号 # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
2. 定义数据模型
使用@Entity
注解来定义你的数据模型。每个模型字段可以用@Column
注解来标记。
import 'package:flora_orm/flora_orm.dart';
@Entity(tableName: 'users')
class User {
@PrimaryKey(autoGenerate: true)
int? id;
@Column(name: 'name')
String name;
@Column(name: 'email')
String email;
// 默认构造函数是必需的,因为ORM库需要它来实例化对象
User({required this.name, required this.email});
// 工厂构造函数可以从Map创建User对象
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
email: json['email'] as String,
);
}
// 将User对象转换为Map
Map<String, dynamic> toJson() {
return {
'name': name,
'email': email,
};
}
}
3. 配置数据库
在你的应用中配置数据库连接。
import 'package:flutter/material.dart';
import 'package:flora_orm/flora_orm.dart';
import 'user_model.dart'; // 假设你的User模型定义在这个文件中
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 配置数据库
final database = await FloraDatabase.connect(
databasesPath: 'path_to_your_databases_directory', // 可以是getDatabasesPath()返回的路径
databaseName: 'my_database.db',
);
// 注册实体
database.registerEntities(<Type>[User]);
// 创建表(如果尚不存在)
await database.open();
runApp(MyApp(database: database));
}
class MyApp extends StatelessWidget {
final FloraDatabase database;
MyApp({required this.database});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flora ORM Example'),
),
body: Center(
child: MyHomePage(database: database),
),
),
);
}
}
4. 执行数据库操作
在你的主页面(或任何其他组件)中执行数据库操作,如插入、查询、更新和删除。
import 'package:flutter/material.dart';
import 'package:flora_orm/flora_orm.dart';
import 'user_model.dart';
class MyHomePage extends StatefulWidget {
final FloraDatabase database;
MyHomePage({required this.database});
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
_insertUser();
}
Future<void> _insertUser() async {
final user = User(name: 'John Doe', email: 'john.doe@example.com');
await widget.database.insert(user);
print('User inserted');
}
Future<void> _fetchUsers() async {
final users = await widget.database.query<User>();
print('Fetched users: $users');
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
// 执行查询操作
await _fetchUsers();
},
child: Text('Fetch Users'),
);
}
}
在这个示例中,我们演示了如何定义一个简单的User
模型,配置数据库连接,并在初始化时插入一个用户,以及如何通过按钮点击事件来查询所有用户。
注意:在实际应用中,你可能会希望将数据库操作封装在更具体的服务类中,并在UI层调用这些服务。此外,错误处理和用户反馈也是实际应用中需要考虑的重要因素。