flutter-drift

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Flutter Drift

Flutter Drift

Comprehensive guide for using drift database library in Flutter applications.
Flutter应用中使用drift数据库库的全面指南。

Overview

概述

Flutter Drift skill provides complete guidance for implementing persistent local storage in Flutter apps using the drift library. Drift is a reactive persistence library for Flutter built on SQLite, offering type-safe queries, auto-updating streams, schema migrations, and cross-platform support.
Flutter Drift 指南为使用drift库在Flutter应用中实现持久化本地存储提供完整指导。Drift是基于SQLite的Flutter响应式持久化库,提供类型安全查询、自动更新流、模式迁移和跨平台支持。

Quick Start

快速开始

Add dependencies to
pubspec.yaml
:
yaml
dependencies:
  drift: ^2.30.0
  drift_flutter: ^0.2.8
  path_provider: ^2.1.5

dev_dependencies:
  drift_dev: ^2.30.0
  build_runner: ^2.10.4
Define database:
dart
(tables: [TodoItems])
class AppDatabase extends _$AppDatabase {
  AppDatabase([QueryExecutor? e])
      : super(
          e ??
              driftDatabase(
                name: 'app_db',
                native: const DriftNativeOptions(
                  databaseDirectory: getApplicationSupportDirectory,
                ),
                web: DriftWebOptions(
                  sqlite3Wasm: Uri.parse('sqlite3.wasm'),
                  driftWorker: Uri.parse('drift_worker.js'),
                ),
              ),
        );

  
  int get schemaVersion => 1;
}
Run code generator:
bash
dart run build_runner build
pubspec.yaml
添加依赖:
yaml
dependencies:
  drift: ^2.30.0
  drift_flutter: ^0.2.8
  path_provider: ^2.1.5

dev_dependencies:
  drift_dev: ^2.30.0
  build_runner: ^2.10.4
定义数据库:
dart
(tables: [TodoItems])
class AppDatabase extends _$AppDatabase {
  AppDatabase([QueryExecutor? e])
      : super(
          e ??
              driftDatabase(
                name: 'app_db',
                native: const DriftNativeOptions(
                  databaseDirectory: getApplicationSupportDirectory,
                ),
                web: DriftWebOptions(
                  sqlite3Wasm: Uri.parse('sqlite3.wasm'),
                  driftWorker: Uri.parse('drift_worker.js'),
                ),
              ),
        );

  
  int get schemaVersion => 1;
}
运行代码生成器:
bash
dart run build_runner build

Reference Files

参考文档

See detailed documentation for each topic:
  • setup.md - Flutter-specific setup with drift_flutter
  • tables.md - Table definitions, columns, constraints
  • queries.md - SELECT, WHERE, JOIN, aggregations
  • writes.md - INSERT, UPDATE, DELETE, transactions
  • streams.md - Reactive stream queries
  • migrations.md - Database schema migrations
  • flutter-ui.md - Flutter UI integration patterns
查看各主题的详细文档:
  • setup.md - 基于drift_flutter的Flutter专属设置
  • tables.md - 表定义、列、约束
  • queries.md - SELECT、WHERE、JOIN、聚合操作
  • writes.md - INSERT、UPDATE、DELETE、事务
  • streams.md - 响应式流查询
  • migrations.md - 数据库模式迁移
  • flutter-ui.md - Flutter UI集成模式

Common Patterns

常见模式

Reactive Todo List with StreamBuilder

使用StreamBuilder实现响应式待办事项列表

dart
class TodoList extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final database = Provider.of<AppDatabase>(context);

    return StreamBuilder<List<TodoItem>>(
      stream: select(database.todoItems).watch(),
      builder: (context, snapshot) {
        final todos = snapshot.data ?? [];
        return ListView.builder(
          itemCount: todos.length,
          itemBuilder: (context, index) {
            final todo = todos[index];
            return ListTile(
              title: Text(todo.title),
              trailing: Checkbox(
                value: todo.isCompleted,
                onChanged: (value) {
                  database.update(database.todoItems).replace(
                    TodoItem(
                      id: todo.id,
                      title: todo.title,
                      isCompleted: value ?? false,
                    ),
                  );
                },
              ),
            );
          },
        );
      },
    );
  }
}
dart
class TodoList extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final database = Provider.of<AppDatabase>(context);

    return StreamBuilder<List<TodoItem>>(
      stream: select(database.todoItems).watch(),
      builder: (context, snapshot) {
        final todos = snapshot.data ?? [];
        return ListView.builder(
          itemCount: todos.length,
          itemBuilder: (context, index) {
            final todo = todos[index];
            return ListTile(
              title: Text(todo.title),
              trailing: Checkbox(
                value: todo.isCompleted,
                onChanged: (value) {
                  database.update(database.todoItems).replace(
                    TodoItem(
                      id: todo.id,
                      title: todo.title,
                      isCompleted: value ?? false,
                    ),
                  );
                },
              ),
            );
          },
        );
      },
    );
  }
}

Add Item with Form

使用表单添加项目

dart
Future<void> showAddTodoDialog(BuildContext context) async {
  final controller = TextEditingController();
  final database = Provider.of<AppDatabase>(context);

  await showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text('Add Todo'),
        content: TextField(
          controller: controller,
          decoration: const InputDecoration(labelText: 'Title'),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () async {
              if (controller.text.isNotEmpty) {
                await database.into(database.todoItems).insert(
                  TodoItemsCompanion.insert(title: controller.text),
                );
                if (context.mounted) {
                  Navigator.pop(context);
                }
              }
            },
            child: const Text('Add'),
          ),
        ],
      );
    },
  );

  controller.dispose();
}
dart
Future<void> showAddTodoDialog(BuildContext context) async {
  final controller = TextEditingController();
  final database = Provider.of<AppDatabase>(context);

  await showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text('Add Todo'),
        content: TextField(
          controller: controller,
          decoration: const InputDecoration(labelText: 'Title'),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () async {
              if (controller.text.isNotEmpty) {
                await database.into(database.todoItems).insert(
                  TodoItemsCompanion.insert(title: controller.text),
                );
                if (context.mounted) {
                  Navigator.pop(context);
                }
              }
            },
            child: const Text('Add'),
          ),
        ],
      );
    },
  );

  controller.dispose();
}

Provider Setup

Provider配置

dart
final databaseProvider = Provider<AppDatabase>((ref) {
  final database = AppDatabase();
  ref.onDispose(database.close);
  return database;
});
dart
final databaseProvider = Provider<AppDatabase>((ref) {
  final database = AppDatabase();
  ref.onDispose(database.close);
  return database;
});

Database Migration

数据库迁移

dart

MigrationStrategy get migration {
  return MigrationStrategy(
      onUpgrade: stepByStep(
        from1To2: (m, schema) async {
          await m.addColumn(schema.todoItems, schema.todoItems.dueDate);
        },
      ),
    );
}
dart

MigrationStrategy get migration {
  return MigrationStrategy(
      onUpgrade: stepByStep(
        from1To2: (m, schema) async {
          await m.addColumn(schema.todoItems, schema.todoItems.dueDate);
        },
      ),
    );
}

Platform-Specific Setup

平台专属设置

Mobile (Android/iOS/macOS/Windows/Linux)

移动平台(Android/iOS/macOS/Windows/Linux)

Uses
drift_flutter
with
getApplicationSupportDirectory
.
使用
drift_flutter
搭配
getApplicationSupportDirectory

Web

Web平台

Place
sqlite3.wasm
and
drift_worker.js
in
web/
folder.
sqlite3.wasm
drift_worker.js
放置在
web/
文件夹中。

Isolate Sharing

隔离区共享

dart
AppDatabase.defaults(): super(
  driftDatabase(
    name: 'app_db',
    native: DriftNativeOptions(
      shareAcrossIsolates: true,
    ),
  ),
);
dart
AppDatabase.defaults(): super(
  driftDatabase(
    name: 'app_db',
    native: DriftNativeOptions(
      shareAcrossIsolates: true,
    ),
  ),
);

Testing

测试

Use in-memory database for tests:
dart
AppDatabase createTestDatabase() {
  return AppDatabase(NativeDatabase.memory());
}
使用内存数据库进行测试:
dart
AppDatabase createTestDatabase() {
  return AppDatabase(NativeDatabase.memory());
}

Best Practices

最佳实践

  1. Use drift_flutter for easy database setup across platforms
  2. StreamBuilder for reactive UI updates
  3. Provider/Riverpod for database access management
  4. Close database on app/widget dispose
  5. Use migrations when schema changes
  6. Index columns used in WHERE clauses
  7. Limit stream query size for performance
  8. Use transactions for multi-step operations
  9. Debounce user input for search/filter
  10. Handle loading/error states in UI
  1. 使用drift_flutter 实现跨平台的简易数据库设置
  2. StreamBuilder 用于响应式UI更新
  3. Provider/Riverpod 用于数据库访问管理
  4. 在应用/组件销毁时关闭数据库
  5. 模式变更时使用迁移
  6. 为WHERE子句中使用的列添加索引
  7. 限制流查询的大小以提升性能
  8. 多步骤操作使用事务
  9. 搜索/过滤时防抖用户输入
  10. 在UI中处理加载/错误状态

Troubleshooting

故障排除

Build Fails

构建失败

bash
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
bash
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs

Migration Errors

迁移错误

bash
dart run drift_dev schema validate
dart run drift_dev make-migrations
bash
dart run drift_dev schema validate
dart run drift_dev make-migrations

Stream Not Updating

流未更新

Ensure operations go through drift APIs, not raw SQLite.
确保操作通过drift API执行,而非原生SQLite。