目录
- 参考
- 正文核心API
- 写入(更新、插入、删除)
- 1.更新和删除
- 2.使用 SQL 表达式更新
- 3.插入件
- 4.更新插入
- 5.返回
参考
- https://drift.simonbinder.eu/dart_api/writes/#updating-with-sql-expressions
正文核心API
写入(更新、插入、删除)
1.更新和删除
您可以使用生成的类来更新任何行的单个字段:
Future moveImportantTasksIntoCategory(Category target) {
// for updates, we use the "companion" version of a generated class. This wraps the
// fields in a "Value" type which can be set to be absent using "Value.absent()". This
// allows us to separate between "SET category = NULL" (`category: Value(null)`) and not
// updating the category at all: `category: Value.absent()`.
return (update(todos)
..where((t) => t.title.like('%Important%'))
).write(TodosCompanion(
category: Value(target.id),
),
);
}
Future updateTodo(Todo entry) {
// using replace will update all fields from the entry that are not marked as a primary key.
// it will also make sure that only the entry with the same primary key will be updated.
// Here, this means that the row that has the same id as entry will be updated to reflect
// the entry's title, content and category. As its where clause is set automatically, it
// cannot be used together with where.
return update(todos).replace(entry);
}
Future feelingLazy() {
// 删除id小于10的所有对象
return (delete(todos)..where((t) => t.id.isSmallerThanValue(10))).go();
}
- 注意:如果您没有明确添加where更新或删除子句,则该语句将影响表中的所有行!
2.使用 SQL 表达式更新
在某些情况下,您可能需要根据当前值更新多行。一种方案是先将受影响的行选择到 Dart 对象中,然后根据这些结果创建伴随对象并用于更新。如果更新可以用 SQL 描述,则可以使用更高效的方法Companion.custom:
await db
.update(db.users)
.write(UsersCompanion.custom(username: db.users.username.lower()));
这里,表name中users所有现有行的列均更改为小写。由于.lower()列的逐一替换功能已在数据库中实现,因此无需在语句执行过程中将行加载到 Dart 中。
3.插入件
您可以非常轻松地将任何有效对象插入表中。由于某些值可能不存在(例如我们无需明确设置的默认值),我们再次使用配套版本。
// returns the generated id
Future<int> addTodo(TodosCompanion entry) {
return into(todos).insert(entry);
}
生成的所有行类都会有一个可用于创建对象的构造函数:
addTodo(
TodosCompanion(
title: Value('Important task'),
content: Value('Refactor persistence code'),
),
);
如果某个列可空或具有默认值(包括自增列),则可以省略该字段。所有其他字段必须已设置且非空。insert否则,该方法将抛出异常。
可以使用批处理高效地运行多个插入语句。为此,您可以使用insertAll中的方法batch:
Future<void> insertMultipleEntries() async{
await batch((batch) {
// functions in a batch don't have to be awaited - just
// await the whole batch afterwards.
batch.insertAll(todos, [
TodosCompanion.insert(
title: 'First entry',
content: 'My content',
),
TodosCompanion.insert(
title: 'Another entry',
content: 'More content',
// columns that aren't required for inserts are still wrapped in a Value:
category: Value(3),
),
// ...
]);
});
}
批处理与事务类似,所有更新操作都以原子方式进行,但批处理支持进一步优化,避免重复准备相同的 SQL 语句。这使得批处理非常适合批量插入或更新操作。
4.更新插入
Upserts 是较新版本的 sqlite3 中的一项功能,如果已经存在冲突的行,则它允许插入像更新一样运行。
当主键是其数据的一部分时,这允许我们创建或覆盖现有行:
class Users extends Table {
TextColumn get email => text()();
TextColumn get name => text()();
Set<Column> get primaryKey => {email};
}
Future<int> createOrUpdateUser(User user) {
return into(users).insertOnConflictUpdate(user);
}
当使用已存在的电子邮件地址进行呼叫时createOrUpdateUser(),该用户的姓名将被更新。否则,新的用户将被插入数据库。
插入操作也可以用于更高级的查询。例如,假设我们正在构建一个字典,并希望跟踪某个单词的出现次数。一个用于此目的的表可能如下所示
class Words extends Table {
TextColumn get word => text()();
IntColumn get usages => integer().withDefault(const Constant(1))();
Set<Column> get primaryKey => {word};
}
通过使用自定义的 upserts,我们可以插入一个新单词,或者usages 如果它已经存在则增加它的计数器:
Future<void> trackWord(String word) {
return into(words).insert(
WordsCompanion.insert(word: word),
onConflict: DoUpdate(
(old) => WordsCompanion.custom(usages: old.usages + Constant(1))),
);
}
5.返回
您可以使用insertReturning插入一行或伴随行,并立即获取插入的行。返回的行包含所有生成的默认值和递增 ID。
注意:此方法使用了RETURNINGsqlite3 3.35 版新增的语法,该语法在大多数操作系统上默认不可用。使用此方法时,请确保您拥有最新的 sqlite3 版本。以下情况也是如此sqlite3_flutter_libs。
例如,考虑使用入门指南中的表格的以下代码片段:
final row = await into(todos).insertReturning(TodosCompanion.insert(
title: 'A todo entry',
content: 'A description',
));
返回row的 具有正确的id设置。如果表有其他默认值,包括像 这样的动态值CURRENT_TIME,那么这些值也会在 所返回的行中设置insertReturning。