254 lines
5.3 KiB
Markdown
254 lines
5.3 KiB
Markdown
---
|
|
title: Insert, Update, Delete
|
|
description: Implement Drift writes, companions, transactions, and batches
|
|
---
|
|
|
|
## Scope Rule
|
|
|
|
From Flutter code outside the database class, call write builders on the database instance:
|
|
|
|
```dart
|
|
await database.into(database.todoItems).insert(
|
|
TodoItemsCompanion.insert(title: title),
|
|
);
|
|
```
|
|
|
|
Use bare `into(todoItems)`, `update(todoItems)`, and `delete(todoItems)` only inside `GeneratedDatabase` or `DatabaseAccessor` code.
|
|
|
|
## Insert
|
|
|
|
Insert a row with required values:
|
|
|
|
```dart
|
|
final id = await database.into(database.todoItems).insert(
|
|
TodoItemsCompanion.insert(
|
|
title: 'First todo',
|
|
content: const Value('Some description'),
|
|
),
|
|
);
|
|
```
|
|
|
|
Omit nullable columns and columns with SQL defaults:
|
|
|
|
```dart
|
|
final id = await database.into(database.todoItems).insert(
|
|
TodoItemsCompanion.insert(title: 'First todo'),
|
|
);
|
|
```
|
|
|
|
Insert multiple rows in a batch:
|
|
|
|
```dart
|
|
await database.batch((batch) {
|
|
batch.insertAll(database.todoItems, [
|
|
TodoItemsCompanion.insert(title: 'First entry'),
|
|
TodoItemsCompanion.insert(
|
|
title: 'Another entry',
|
|
priority: const Value(2),
|
|
),
|
|
]);
|
|
});
|
|
```
|
|
|
|
## Upsert
|
|
|
|
Use `insertOnConflictUpdate` when the row has a primary key or unique key that should be replaced on conflict.
|
|
|
|
```dart
|
|
await database.into(database.todoItems).insertOnConflictUpdate(
|
|
TodoItemsCompanion.insert(
|
|
id: const Value(1),
|
|
title: 'Updated title',
|
|
),
|
|
);
|
|
```
|
|
|
|
For custom conflict handling, pass a `DoUpdate` clause with an update companion:
|
|
|
|
```dart
|
|
await database.into(database.todoItems).insert(
|
|
TodoItemsCompanion.insert(
|
|
id: const Value(1),
|
|
title: 'Important',
|
|
),
|
|
onConflict: DoUpdate(
|
|
(old) => const TodoItemsCompanion(
|
|
priority: Value(5),
|
|
),
|
|
),
|
|
);
|
|
```
|
|
|
|
Use `insertReturning` only when the target SQLite runtime supports `RETURNING`.
|
|
|
|
```dart
|
|
final row = await database.into(database.todoItems).insertReturning(
|
|
TodoItemsCompanion.insert(title: 'A todo entry'),
|
|
);
|
|
```
|
|
|
|
## Update
|
|
|
|
Always add a `where` clause unless the intent is truly to update every row.
|
|
|
|
```dart
|
|
await (database.update(database.todoItems)
|
|
..where((t) => t.id.equals(id)))
|
|
.write(
|
|
const TodoItemsCompanion(
|
|
title: Value('Updated title'),
|
|
),
|
|
);
|
|
```
|
|
|
|
Update multiple columns with a companion:
|
|
|
|
```dart
|
|
await (database.update(database.todoItems)
|
|
..where((t) => t.id.equals(id)))
|
|
.write(
|
|
const TodoItemsCompanion(
|
|
title: Value('Updated title'),
|
|
isCompleted: Value(true),
|
|
),
|
|
);
|
|
```
|
|
|
|
Use `replace` only when you have a complete generated data row:
|
|
|
|
```dart
|
|
await database.update(database.todoItems).replace(
|
|
todo.copyWith(isCompleted: true),
|
|
);
|
|
```
|
|
|
|
Use custom expressions for SQL-side updates:
|
|
|
|
```dart
|
|
await (database.update(database.todoItems)
|
|
..where((t) => t.id.equals(id)))
|
|
.write(
|
|
TodoItemsCompanion.custom(
|
|
priority: database.todoItems.priority + const Constant(1),
|
|
),
|
|
);
|
|
```
|
|
|
|
## Delete
|
|
|
|
Delete matching rows with `where` and `go()`:
|
|
|
|
```dart
|
|
await (database.delete(database.todoItems)
|
|
..where((t) => t.id.equals(id)))
|
|
.go();
|
|
```
|
|
|
|
Delete multiple rows:
|
|
|
|
```dart
|
|
await (database.delete(database.todoItems)
|
|
..where((t) => t.isCompleted.equals(true)))
|
|
.go();
|
|
```
|
|
|
|
Delete all rows only when that is explicitly intended:
|
|
|
|
```dart
|
|
await database.delete(database.todoItems).go();
|
|
```
|
|
|
|
Do not use `delete(table).go(id)`. That is not Drift's delete API.
|
|
|
|
## Companions And Value
|
|
|
|
Generated data classes represent full rows. Companions represent partial writes.
|
|
|
|
```dart
|
|
final companion = TodoItemsCompanion(
|
|
title: const Value('Title'),
|
|
content: const Value('Content'),
|
|
priority: const Value(2),
|
|
category: const Value.absent(),
|
|
);
|
|
```
|
|
|
|
For nullable fields, distinguish setting `NULL` from leaving a column unchanged:
|
|
|
|
```dart
|
|
const TodoItemsCompanion(
|
|
category: Value<int?>(null),
|
|
);
|
|
|
|
const TodoItemsCompanion(
|
|
category: Value.absent(),
|
|
);
|
|
```
|
|
|
|
## Transactions
|
|
|
|
Use transactions for multi-step writes that must succeed or fail together.
|
|
|
|
```dart
|
|
final categoryId = await database.transaction(() async {
|
|
final id = await database.into(database.categories).insert(
|
|
CategoriesCompanion.insert(name: 'Work'),
|
|
);
|
|
|
|
await database.into(database.todoItems).insert(
|
|
TodoItemsCompanion.insert(
|
|
title: 'First work todo',
|
|
category: Value(id),
|
|
),
|
|
);
|
|
|
|
return id;
|
|
});
|
|
```
|
|
|
|
Errors thrown inside the callback roll the transaction back.
|
|
|
|
## Batch Operations
|
|
|
|
Batches are useful for many similar writes.
|
|
|
|
```dart
|
|
await database.batch((batch) {
|
|
batch.insertAll(database.todoItems, [
|
|
TodoItemsCompanion.insert(title: 'First'),
|
|
TodoItemsCompanion.insert(title: 'Second'),
|
|
]);
|
|
|
|
batch.update(
|
|
database.todoItems,
|
|
const TodoItemsCompanion(priority: Value(1)),
|
|
where: (t) => t.isCompleted.equals(false),
|
|
);
|
|
|
|
batch.deleteWhere(
|
|
database.todoItems,
|
|
(t) => t.isCompleted.equals(true),
|
|
);
|
|
});
|
|
```
|
|
|
|
Use `batch.delete(table, row)` only when you have an insertable row with the primary key. Use `batch.deleteWhere` for predicates.
|
|
|
|
## Write Safety
|
|
|
|
Avoid broad updates and deletes in UI actions:
|
|
|
|
```dart
|
|
// Bad: updates every todo.
|
|
await database.update(database.todoItems).write(
|
|
const TodoItemsCompanion(isCompleted: Value(true)),
|
|
);
|
|
|
|
// Good: updates one row.
|
|
await (database.update(database.todoItems)
|
|
..where((t) => t.id.equals(id)))
|
|
.write(
|
|
const TodoItemsCompanion(isCompleted: Value(true)),
|
|
);
|
|
```
|