Flutter笔记 用于ORM的Floor框架简记
本文地址:
floor 模块地址:https://pub.dev/packages/floor
【介绍】:最近想找用于Dart和Flutter的ORM框架,偶然间发现了Floor,觉得还不错,做一些记录。
- 1. Floor 框架概述
- 1.1 框架简介
- 1.2 框架的构成
- 1.3 安装
- 1.4 架构体系
- 2. 实体(Entity)
- 支持的类型
- 主键
- 外键
- 索引
- 忽略字段
- 继承
- 数据库视图(Database Views)
- 3. 数据访问对象(DAO - Data Access Object)
- 4. 创建数据库
- 5. 运行代码生成器
- 6. 使用生成的代码
- 附录:Floor中的部分源码解析
- Entity
- DAO
- ForeignKey
- Database
- DatabaseView
- ColumnInfo
- Index
- Query
- Insert
- Update
- _Transaction
- _Delete
- _Ignore
1. Floor 框架概述
1.1 框架简介
Floor 框架是一个用于在 Flutter 应用程序中使用 SQLite 数据库的开源库。它允许开发者轻松地将本地数据库集成到其应用程序中,并提供了一种类型安全、高效和易于使用的方法来执行数据库操作。
1.2 框架的构成
Floor 框架由多个关键模块组成,每个模块都有特定的功能,协同工作以实现在 Flutter 应用程序中使用 SQLite 数据库的目标。以下是 Floor 框架的主要模块以及它们的作用:
- floor(运行时库):
- 作用:
floor
是 Floor 框架的运行时库,包含用于运行时数据库操作的类和方法。 - 关键类和方法:
-
FloorDatabase
:抽象类,表示数据库的根类,生成的数据库类需要扩展它。 -
@Database
:用于标记生成的数据库类,指定数据库版本号、实体列表和其他配置信息。 -
databaseBuilder
:用于创建数据库实例的方法。 - 数据库操作方法:生成的数据库类中包含与数据库表的交互方法,例如插入、查询、更新等。
- floor_generator(代码生成器):
- 作用:
floor_generator
是 Floor 框架的代码生成器模块,它会根据实体和 DAO 的定义生成数据库访问代码。 - 生成的代码: 该模块生成包括数据库类、DAO 类以及其他与数据库交互相关的代码,使开发者能够轻松执行数据库操作,而无需手动编写大量的重复代码。
- floor_annotation(Floor 框架中的注解)
- 作用: floor_annotation是Floor 框架中的注解。这些注解用于标记和配置数据库实体(Entities)、数据访问对象(DAOs)以及数据库操作,以便 Floor 框架的代码生成器 floor_generator 可以根据这些注解生成相应的数据库访问代码。
- floor_annotation 提供了一种类型安全的方式来配置和定义数据库操作,并允许开发者在 Dart 代码中使用注解来描述数据库模型和操作,而无需手动编写大量的重复代码。
- 例如:
- @entity:用于标记 Dart 类,表示它是一个数据库实体(Entity)。实体类通常与数据库表相对应,用于定义表的结构和字段。
- @dao:用于标记抽象类或接口,表示它是数据访问对象(DAO)。DAO 类包含了与数据库表相关的操作方法,如插入、查询、更新和删除。
等等
- sqflite(数据库驱动,由floor自动调用):
- 作用: Floor 框架依赖于
sqflite
插件,它提供了在 Flutter 中与 SQLite 数据库进行底层交互的功能。 -
sqflite
插件负责管理 SQLite 数据库文件、执行原始 SQL 查询和处理数据库事务。
这些模块协同工作,使开发者能够轻松地在 Flutter 应用程序中集成和操作 SQLite 数据库。通过定义实体、DAO 和数据库,然后运行代码生成器,开发者可以获得类型安全、高效和易于维护的数据库访问代码,从而实现数据持久化和本地数据存储的需求。
- build_runner:build_runner 通常与 floor_generator 一起使用,以自动生成与数据库操作相关的 Dart 代码。
1.3 安装
flutter pub add floor
flutter pub add floor_generator build_runner --dev
其中:
-
floor
: 包含了将在应用程序中使用的所有代码。 -
floor_generator
: 包含了生成数据库类的代码。 -
build_runner
: 允许以具体的方式生成源代码文件。
将在你的yaml中看到:
dependencies:
flutter:
sdk: flutter
floor: ^1.4.0
dev_dependencies:
floor_generator: ^1.4.0
build_runner: ^2.1.2
版本可能随时间变化
1.4 架构体系
存储和访问数据的组件是 实体、数据访问对象(DAO) 和 数据库:
- 一个 实体 代表一个 持久类,也就是一个 数据库表;
- Dao管理对实体的访问,并负责内存中 对象 和表行 之间的 映射;
- 数据库是底层 SQLite 数据库的中心访问点。它 保存Dao,除此之外,还负责 初始化数据库及其 模式。
2. 实体(Entity)
一个实体是一个持久化类。Floor 自动创建内存中对象与数据库表行之间的映射。可以通过向 Entity 注释添加可选值来向 Floor 提供自定义元数据。它具有表名 tableName 的附加属性,该属性打开了为特定实体使用自定义名称的可能性,而不是使用类名。foreignKeys 允许向实体添加外键。有关如何使用这些内容的更多信息,请参阅外键部分。还支持索引。可以通过将索引添加到实体的 indices 值来使用它们。
-
@entity
注解用于标记了该类为持久类; -
@PrimaryKey
将类的属性标记为主键列。该属性必须是 int 类型。当启用autoGenerate
时,SQLite 可以自动生成该值; - 必须通过将
@primaryKey
注解添加到一个int
属性上为你的表添加一个主键,例如:
// entity/person.dart
import 'package: floor/floor.dart';
@entity
class Person {
@primaryKey
final int id;
final String name;
Person(this.id, this.name);
}
-
@ColumnInfo
使单个表列的自定义映射变得可能。使用该注释,可以为列指定自定义名称。如果要将表的列设置为可空,请将实体字段标记为可空; - Floor 自动使用实体类中定义的第一个构造函数来从数据库行创建内存中对象
注:
Entity的属性 | 类型 | 默认值 | 描述 |
tableName | String? | null | 用于指定数据库中的表名。如果不指定,那么表名默认为实体类的类名。 |
indices | List | [] | 用于为实体添加索引。索引可以提高数据库查询的速度。每个Index对象代表一个索引,它包含一个字段名列表和一个表示索引是否唯一的布尔值。 |
foreignKeys | List | [] | 用于为实体添加外键。外键是数据库中的一个重要概念,它用来建立两个表之间的关联。每个ForeignKey对象代表一个外键,它包含一个子列名列表、一个父列名列表和一个引用的实体类。 |
primaryKeys | List | [] | 用于指定实体的主键列。主键是数据库中的一个重要概念,它用来唯一标识表中的每一行。 |
withoutRowid | bool | false | 用于指定表是否为 “WITHOUT ROWID” 表。“WITHOUT ROWID” 表是SQLite的一个特性,它可以提高某些查询的速度,但是也有一些限制。 |
支持的类型
Floor 实体可以保存以下 Dart 类型的值,这些类型与它们对应的 SQLite 类型相互映射。
-
int
- INTEGER -
double
- REAL -
String
- TEXT -
bool
- INTEGER(0 = false,1 = true) -
Uint8List
- BLOB -
enum
- INTEGER(按索引 0…n 记录)
如果要存储可以由上述类型之一表示的复杂 Dart 对象,请查看类型转换器。
主键
每当需要复合主键(例如 n-m 关系)时,设置主键的语法与前面提到的设置主键的方式不同。不是使用 @PrimaryKey
注释字段,而是使用 @Entity
注释的 primaryKey 属性。它接受一个由列名组成的列表,这些列名组成复合主键。
@Entity(primaryKeys: ['id', 'name'])
class Person {
final int id;
final String name;
Person(this.id, this.name);
}
外键
向引用实体的 Entity 注释添加 ForeignKeys 列表。childColumns 定义当前实体的列,而 parentColumns 定义父实体的列。在 onUpdate 和 onDelete 属性中定义外键操作后,可以触发外键操作。
// Dog 类,表示数据库中的狗实体
@Entity(
tableName: 'dog', // 指定表名为 'dog'
foreignKeys: [
ForeignKey(
childColumns: ['owner_id'], // 子列名为 'owner_id'
parentColumns: ['id'], // 父列名为 'id'
entity: Person, // 引用的实体为 Person 类
)
],
)
class Dog {
@PrimaryKey() // PrimaryKey 注解,将 id 标记为主键列
final int id;
final String name; // 名称
@ColumnInfo(name: 'owner_id') // ColumnInfo 注解,自定义列名为 'owner_id'
final int ownerId; // 所有者的 ID
// 构造函数,接受 id、name 和 ownerId 参数
Dog(this.id, this.name, this.ownerId);
}
-
@Entity
注解标记了Dog
类,指定了表名为 ‘dog’,同时指定了一个外键(foreign key),该外键将在 ‘owner_id’ 列上创建,它引用了另一个实体Person
。这意味着在数据库中将创建名为 ‘dog’ 的表,并在 ‘owner_id’ 列上创建一个外键,以确保数据的完整性。 -
@PrimaryKey
注解标记了id
字段作为主键列,这意味着它在数据库中将用作主键。 -
@ColumnInfo
注解标记了ownerId
字段,并自定义了列名为 ‘owner_id’,这允许在数据库表中使用不同的列名,而不是默认的字段名。 - 构造函数接受
id
、name
和ownerId
参数,并用于创建Dog
实例。
这些注释和注释说明了 Dog
类的结构,以及如何配置表名、外键和自定义列名。
索引
索引有助于加速查询、连接和分组操作。有关 SQLite 索引的更多信息,请参阅官方文档。要在 floor 中创建索引,请将索引列表添加到 @Entity 注释。下面的示例演示了如何在实体的 custom_name 列上创建索引。
此外,可以使用其 name 属性命名索引。要将索引设置为唯一索引,请使用 unique 属性。
// Person 类,表示数据库中的个人实体
@Entity(tableName: 'person', indices: [Index(value: ['custom_name'])])
class Person {
@primaryKey // PrimaryKey 注解,将 id 标记为主键列
final int id;
@ColumnInfo(name: 'custom_name') // ColumnInfo 注解,自定义列名为 'custom_name'
final String name; // 姓名
// 构造函数,接受 id 和 name 参数
Person(this.id, this.name);
}
-
@Entity
注解标记了 Person 类,指定了表名为 ‘person’,同时指定了一个索引,该索引将在 ‘custom_name’ 列上创建。这意味着在数据库中将创建名为 ‘person’ 的表,并在 ‘custom_name’ 列上创建一个索引,以提高查询性能。 -
@primaryKey
注解标记了 id 字段作为主键列,这意味着它在数据库中将用作主键。 -
@ColumnInfo
注解标记了 name 字段,并自定义了列名为 ‘custom_name’,这允许在数据库表中使用不同的列名,而不是默认的字段名。
构造函数接受 id 和 name 参数,并用于创建 Person 实例。
忽略字段
默认情况下,实体的 getter、setter 和所有静态字段都会被忽略,并因此从库的映射中排除。如果要进一步忽略字段,应使用 @ignore 注释,并按以下示例中所示应用它。
// 人员类,表示数据库中的人员实体
class Person {
@primaryKey // PrimaryKey 注解,将 id 标记为主键列
final int id;
final String name; // 姓名
@ignore // Ignore 注解,指定 nickname 字段将被忽略
String nickname; // 昵称
// 默认情况下被忽略的字段,不会包含在库的映射中
String get combinedName => "$name ($nickname)";
// 构造函数,接受 id 和 name 参数
Person(this.id, this.name);
}
继承
与 Dao 一样,实体(和数据库视图)可以从共同的基类继承并使用它们的字段。实体只需扩展基类。这个构造将被视为如果基类的所有字段都是实体的一部分,这意味着数据库表将包含实体和基类的所有列。
基类不必为类单独注释。它的字段可以像正常的实体列一样进行注释。外键和索引必须在实体中声明,不能在基类中定义。
// 基础对象类,用于继承到其他实体
class BaseObject {
// 主键标记,指定 id 作为主键列
@PrimaryKey()
final int id;
// ColumnInfo 注解,用于自定义列名 create_time
@ColumnInfo(name: 'create_time')
final String createTime;
// ColumnInfo 注解,用于自定义列名 update_time
@ColumnInfo(name: 'update_time')
final String updateTime;
// 构造函数,接受 id、updateTime 和可选的 createTime 参数
BaseObject(
this.id,
this.updateTime, {
String createTime,
}) : this.createTime = createTime ?? DateTime.now().toString();
// 重写父类的 props 方法,通常用于数据比较
@override
List<Object> get props => [];
}
// Comment 类,继承自 BaseObject 类
@Entity(tableName: 'comments') // Entity 注解,指定表名为 'comments'
class Comment extends BaseObject {
final String author; // 评论作者
final String content; // 评论内容
// 构造函数,接受 author、可选的 id、content、createTime 和 updateTime 参数
Comment(
this.author, {
int id,
this.content = '', // 默认为空字符串
String createTime,
String updateTime,
}) : super(id, updateTime, createTime: createTime); // 调用父类构造函数,传递 id、updateTime 和 createTime 参数
}
数据库视图(Database Views)
如果希望定义返回与实体不同类型的静态 SELECT 语句,最佳选择是使用 @DatabaseView
。数据库视图可以被理解为虚拟表,可以像真实表一样进行查询。
在 Floor 中,数据库视图的定义和使用方式与实体类似,主要区别在于只读访问,这意味着无法执行更新、插入和删除操作。与实体类似,如果未设置 viewName,则使用类名。
@DatabaseView('SELECT distinct(name) AS name FROM person', viewName: 'name')
class Name {
final String name;
Name(this.name);
}
数据库视图不具有任何外键、主键或索引。相反,您应该手动定义与您的语句匹配的索引,并将它们放入涉及实体的 @Entity
注释中。
与实体类似,setter、getter 和静态字段将自动被忽略(与实体类似),您可以使用 @ignore
注解来指定要忽略的附加字段。
在代码中定义数据库视图后,您需要将它添加到 @Database
注释的 views 字段中:
@Database(version: 1, entities: [Person], views: [Name])
abstract class AppDatabase extends FloorDatabase {
// DAO 获取器
}
然后,您可以通过 DAO 函数查询视图,就像查询实体一样。
数据库视图可以像实体一样从基类继承共同字段。
现在可以从 DAO 方法返回一个 Stream 对象,该方法查询数据库视图。但是,它将在整个数据库中的任何
@update
、@insert
、@delete
事件触发时发出,这可能会对运行时产生相当大的负担。请仅在明白自己在做什么时才添加它!这主要是因为检测哪些实体涉及到数据库视图的复杂性所致。
3. 数据访问对象(DAO - Data Access Object)
这个组件负责管理对底层的 SQLite 数据库的访问。抽象类包含了查询数据库的方法签名,这些方法必须返回 Future 或 Stream。
你可以通过将 @Query
注解添加到方法上来定义查询。SQL 语句必须放在括号中。方法必须返回你查询的实体的 Future 或 Stream。@insert
标记了一个方法作为插入方法。
// dao/person_dao.dart
import 'package:floor/floor.dart';
@dao
abstract class PersonDao {
// 查询并返回所有的 Person 实体对象列表
@Query('SELECT * FROM Person')
Future<List<Person>> findAllPersons();
// 根据提供的 id 查询并返回匹配的 Person 实体对象
// 这是一个异步数据流,当数据发生变化时,会自动更新
@Query('SELECT * FROM Person WHERE id = :id')
Stream<Person?> findPersonById(int id);
// 将提供的 Person 对象插入到数据库中
// 这是一个异步操作,不返回任何数据
@insert
Future<void> insertPerson(Person person);
}
4. 创建数据库
它必须是一个继承自 FloorDatabase 的抽象类。此外,必须在类的签名中添加 @Database()
。确保将创建的实体添加到 @Database
注解的 entities 属性中。为了使生成的代码工作,还需要添加列出的导入项。
确保在这个文件的导入项下面添加 part ‘database.g.dart’;。重要的是要注意 ‘database’ 必须与数据库定义的文件名进行交换。在这种情况下,文件名命名为 database.dart。
// database.dart
import 'dart:async';
import 'package:floor/floor.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
import 'dao/person_dao.dart';
import 'entity/person.dart';
part 'database.g.dart'; // Floor代码生成器将在这里生成相关的代码
@Database(version: 1, entities: [Person]) // 声明数据库版本号和包含的实体类
abstract class AppDatabase extends FloorDatabase {
PersonDao get personDao; // 获取PersonDao实例,用于执行数据库操作
}
5. 运行代码生成器
使用以下命令来运行生成器:
dart run build_runner build
上面的命令用于在 Flutter 项目中运行代码生成工具以手动构建生成的代码。build命令 只会运行一次生成过程,然后退出。还可以在 Flutter 项目中使用 build_runner 模块的观察模式,以便在开发过程中自动更新生成的代码。如果想要在文件更改时自动运行它,请使用以下命令:
dart run build_runner watch
6. 使用生成的代码
要获取数据库的实例,使用生成的 $FloorAppDatabase 类,它允许访问数据库生成器。名称由 $Floor 和数据库类名组成。传递给 databaseBuilder() 的字符串将是数据库文件的名称。要初始化数据库,调用 build() 并确保等待结果。
为了检索 PersonDao 实例,只需在数据库实例上调用 persoDao getter 即可。
可以参考下面的代码。
// 使用数据库生成器创建数据库实例,传递数据库文件的名称('app_database.db')
final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();
// 从数据库实例中获取 PersonDao 实例
final personDao = database.personDao;
// 创建一个 Person 对象
final person = Person(1, 'Frank');
// 将新的 Person 对象插入到数据库中
await personDao.insertPerson(person);
// 通过 ID 查找数据库中的 Person 记录
final result = await personDao.findPersonById(1);
// 输出查找到的 Person 记录
print('Found Person: $result');
附录:Floor中的部分源码解析
Entity
import 'package:floor_annotation/src/foreign_key.dart';
import 'package:floor_annotation/src/index.dart';
/// 将类标记为数据库实体(表)。
class Entity {
/// SQLite表的表名。
final String? tableName;
/// 表上的索引列表。
final List<Index> indices;
/// 此实体上的[ForeignKey]约束列表。
final List<ForeignKey> foreignKeys;
/// 主键列名列表。
final List<String> primaryKeys;
/// 表是否为 "WITHOUT ROWID table"。
final bool withoutRowid;
/// 将类标记为数据库实体(表)。
const Entity({
this.tableName,
this.indices = const [],
this.foreignKeys = const [],
this.primaryKeys = const [],
this.withoutRowid = false,
});
}
/// 将类标记为数据库实体(表)。
const entity = Entity();
Entity类用于标记一个类作为数据库的实体(表)。Entity类有几个属性,包括tableName(表名)、indices(索引列表)、foreignKeys(外键约束列表)、primaryKeys(主键列名列表)和withoutRowid(表是否为 “WITHOUT ROWID table”)。
DAO
class _Dao {
const _Dao();
}
/// 将类标记为数据访问对象。
///
/// 数据访问对象是定义数据库交互的主要类。它们可以包含各种查询方法。
/// 使用@dao标记的类应该是一个抽象类。在编译时,当它被数据库引用时,Floor将生成这个类的实现。
///
/// 建议在你的代码库中有多个Dao类,取决于它们触及的表。
const dao = _Dao();
@dao用于将一个类标记为数据访问对象(DAO)。DAO是你定义数据库交互的主要类,它们可以包含各种查询方法。使用@dao标记的类应该是一个抽象类,Floor会在编译时为这个类生成实现。
ForeignKey
/// 在另一个[Entity]上声明外键。
class ForeignKey {
/// 当前[Entity]中的列名列表。
final List<String> childColumns;
/// 父[Entity]中的列名列表。
final List<String> parentColumns;
/// 要引用的父实体。
final Type entity;
/// [ForeignKeyAction]
/// 当从数据库更新父[Entity]时采取的操作。
///
/// 默认情况下,使用[ForeignKeyAction.noAction]。
final ForeignKeyAction onUpdate;
/// [ForeignKeyAction]
/// 当从数据库删除父[Entity]时采取的操作。
///
/// 默认情况下,使用[ForeignKeyAction.noAction]。
final ForeignKeyAction onDelete;
/// 在另一个[Entity]上声明外键。
const ForeignKey({
required this.childColumns,
required this.parentColumns,
required this.entity,
this.onUpdate = ForeignKeyAction.noAction,
this.onDelete = ForeignKeyAction.noAction,
});
}
/// 用于[ForeignKey.onDelete]和[ForeignKey.onUpdate]的值的常量定义
enum ForeignKeyAction {
/// [ForeignKey.onDelete]或[ForeignKey.onUpdate]的可能值。
///
/// 当父键从数据库中修改或删除时,不采取特殊操作。这意味着SQLite不会做任何努力来修复约束失败,而是拒绝更改。
noAction,
/// [ForeignKey.onDelete]或[ForeignKey.onUpdate]的可能值。
///
/// RESTRICT操作意味着应用程序被禁止删除(对于[ForeignKey.onDelete])或修改(对于[ForeignKey.onUpdate])父键,当存在一个或多个映射到它的子键时。RESTRICT操作的效果与正常的外键约束执行的区别在于,RESTRICT操作的处理发生在字段更新后立即发生 - 不是在当前语句结束时,就像立即约束一样,或者在当前事务结束时,就像延迟()约束一样。
///
/// 即使附加的外键约束是延迟()的,配置RESTRICT操作也会导致SQLite在删除或修改具有依赖子键的父键时立即返回错误。
restrict,
/// [ForeignKey.onDelete]或[ForeignKey.onUpdate]的可能值。
///
/// 如果配置的操作是'SET NULL',那么当父键被删除(对于[ForeignKey.onDelete])或修改(对于[ForeignKey.onUpdate])时,映射到父键的子表中所有行的子键列都被设置为包含NULL值。
setNull,
/// [ForeignKey.onDelete]或[ForeignKey.onUpdate]的可能值。
///
/// 'SET DEFAULT'操作与SET_NULL类似,只是每个子键列被设置为包含列的默认值,而不是NULL。
setDefault,
/// [ForeignKey.onDelete]或[ForeignKey.onUpdate]的可能值。
///
/// 'CASCADE'操作将父键上的删除或更新操作传播到每个依赖的子键。对于[ForeignKey.onDelete]操作,这意味着与删除的父行关联的子实体中的每一行也被删除。对于[ForeignKey.onUpdate]操作,这意味着存储在每个依赖子键中的值被修改以匹配新的父键值。
cascade,
}
在这段代码中,ForeignKey类用于在一个实体上声明外键。ForeignKeyAction枚举定义了可以在ForeignKey.onDelete和ForeignKey.onUpdate中使用的值,这些值表示当父实体被删除或更新时应该采取的操作。
Database
/// 将类标记为FloorDatabase。
class Database {
/// 数据库版本。
final int version;
/// 数据库管理的实体。
final List<Type> entities;
/// 数据库管理的视图。
final List<Type> views;
/// 将类标记为FloorDatabase。
const Database({
required this.version,
required this.entities,
this.views = const [],
});
}
在这段代码中,Database类用于标记一个类作为Floor数据库。Database类有几个属性,包括version(数据库版本)、entities(数据库管理的实体)和views(数据库管理的视图)。
DatabaseView
/// 将类标记为数据库视图(固定的select语句)。
class DatabaseView {
/// SQLite视图的表名。
final String? viewName;
/// 视图基于的SELECT查询。
final String query;
/// 将类标记为数据库视图(固定的select语句)。
const DatabaseView(
this.query, {
this.viewName,
});
}
DatabaseView 类用于标记一个类作为数据库视图。数据库视图是一个固定的 SELECT 语句,它可以像表一样被查询。DatabaseView 类有两个属性,viewName 用于指定视图的名字,query 是视图基于的 SELECT 查询。
ColumnInfo
/// 允许自定义与此字段关联的列。
class ColumnInfo {
/// 列的自定义名称。
final String? name;
const ColumnInfo({this.name});
}
ColumnInfo类用于自定义与字段关联的列。ColumnInfo类有一个属性name,可以用来指定列的自定义名称。
Index
/// 在实体上声明一个索引。
/// 参见:<a href="https://sqlite.org/lang_createindex.html">SQLite索引文档</a>
class Index {
/// 索引的名称。
///
/// 如果未设置,floor将其设置为由'_'连接的列列表,并以'index_$tableName'为前缀。
/// 所以如果你有一个名为"Foo"的表,并有一个索引{"bar", "baz"},生成的索引名称将是
/// 'index_Foo_bar_baz'。如果你需要在查询中指定索引,你永远不应该依赖这个名称,
/// 相反,你应该为你的索引指定一个名称。
final String? name;
/// 如果设置为true,这将是一个唯一索引,任何重复的值将被拒绝。
final bool unique;
/// 索引中的列名列表。
///
/// 列的顺序很重要,因为它定义了SQLite何时可以使用特定的索引。
/// 有关查询优化器中索引使用的详细信息,请参见
/// <a href="https://www.sqlite.org/optoverview.html">SQLite文档</a>。
final List<String> value;
/// 在实体上声明一个索引。
///
/// 默认情况下,不是[unique]。
const Index({this.name, this.unique = false, required this.value});
}
Query
/// 将方法标记为查询方法。
class Query {
/// SQLite查询。
final String value;
/// 将方法标记为查询方法。
const Query(this.value);
}
Query类用于将一个方法标记为查询方法。Query类有一个属性value,它是要执行的SQLite查询。
Insert
import 'package:floor_annotation/src/on_conflict_strategy.dart';
/// 将方法标记为插入方法。
class Insert {
/// 如何处理冲突。默认为 [OnConflictStrategy.abort]。
final OnConflictStrategy onConflict;
/// 将方法标记为插入方法。
const Insert({this.onConflict = OnConflictStrategy.abort});
}
/// 将方法标记为插入方法。
///
/// 默认冲突策略为 [OnConflictStrategy.abort]。
const insert = Insert();
Insert 类和 insert常量用于将一个方法标记为插入方法。Insert 类有一个属性 onConflict,它表示当插入操作发生冲突时应该采取的策略。默认策略是 OnConflictStrategy.abort,表示当发生冲突时应该中止插入操作。
Update
import 'package:floor_annotation/src/on_conflict_strategy.dart';
/// 将方法标记为更新方法。
class Update {
/// 如何处理冲突。默认为 [OnConflictStrategy.abort]。
final OnConflictStrategy onConflict;
/// 将方法标记为更新方法。
const Update({this.onConflict = OnConflictStrategy.abort});
}
/// 将方法标记为更新方法。
///
/// 默认冲突策略为 [OnConflictStrategy.abort]。
const update = Update();
Update 类用于将一个方法标记为更新方法。Update 类有一个属性onConflict,它表示当更新操作引发冲突时应该采取的策略。update 是一个预定义的 Update 类的实例,我们可以直接使用它来标记更新方法。
_Transaction
// 定义一个_Transaction类
class _Transaction {
const _Transaction();
}
// 将方法标记为事务方法
const transaction = _Transaction();
_Transaction 类用于创建一个常量 transaction,这个常量用于将一个方法标记为事务方法。当你在一个方法上使用 transaction 常量时, Floor 框架会知道这个方法是用来执行数据库事务的。
_Delete
// 定义一个_Delete类
class _Delete {
const _Delete();
}
// 将方法标记为删除方法
const delete = _Delete();
_Delete 类用于创建一个常量 delete,这个常量用于将一个方法标记为删除方法。当你在一个方法上使用 delete 常量时,Floor 框架会知道这个方法是用来执行删除操作的。
_Ignore
// 定义一个_Ignore类
class _Ignore {
const _Ignore();
}
// 忽略标记元素的Floor处理逻辑。
// 它只能应用于实体的字段。
const ignore = _Ignore();
_Ignore 类用于创建一个常量 ignore,这个常量用于将实体的某个字段从 Floor 的处理逻辑中排除。当你在一个字段上使用 ignore 常量时, Floor 框架会忽略这个字段,不会对其进行处理。