Flutter数据库管理插件drift_libsql的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter数据库管理插件drift_libsql的使用

简介

drift_libsql 是一个用于Flutter应用程序的Turso/Libsql数据库客户端,基于Drift库。它允许你在Flutter应用中轻松地管理和操作Libsql数据库。本文将详细介绍如何在Flutter项目中使用 drift_libsql 插件,并提供一个完整的示例demo。

准备工作

  1. 添加依赖
    在你的 pubspec.yaml 文件中添加 drift_libsql 依赖:

    dependencies:
      drift_libsql: ^最新版本
    
  2. 创建数据库表
    使用Drift定义数据库表。以下是一个简单的任务表(TaskTable)的定义:

    import 'package:drift/drift.dart';
    
    class TaskTable extends Table {
      IntColumn get id => integer().autoIncrement()(); // 自增ID
      TextColumn get title => text()(); // 任务标题
      TextColumn get description => text().nullable()(); // 任务描述,允许为空
      BoolColumn get completed => boolean().withDefault(const Constant(false))(); // 是否完成,默认为false
    }
    
  3. 创建数据库类
    定义一个继承自 $_AppDatabase 的数据库类,并指定要使用的表和schema版本:

    import 'package:drift/drift.dart';
    import 'package:drift_libsql/drift_libsql.dart';
    import 'dart:io' as io;
    import 'package:path_provider/path_provider.dart';
    
    part 'database.g.dart'; // Drift生成的代码
    
    [@DriftDatabase](/user/DriftDatabase)(tables: [TaskTable])
    class AppDatabase extends _$AppDatabase {
      AppDatabase(super.e);
    
      @override
      int get schemaVersion => 1; // 数据库版本
    
      // 插入任务
      Future<int> insertTask(TaskTableCompanion task) {
        return into(taskTable).insert(task);
      }
    
      // 查询所有任务
      Future<List<Task>> getAllTasks() {
        return (select(taskTable)..orderBy([(t) => OrderingTerm.asc(t.id)])).get();
      }
    
      // 更新任务
      Future<int> updateTask(TaskTableCompanion task) {
        return update(taskTable).replace(task);
      }
    
      // 删除任务
      Future<int> deleteTask(int id) {
        return (delete(taskTable)..where((t) => t.id.equals(id))).go();
      }
    }
    
  4. 初始化数据库
    main.dart 中初始化不同类型的数据库实例(内存、本地、远程和副本)。这里我们使用 path_provider 来获取应用的缓存目录路径,并根据不同的需求创建不同的数据库实例:

    import 'package:drift_libsql/drift_libsql.dart';
    import 'package:flutter/material.dart';
    import 'package:path_provider/path_provider.dart';
    import 'database.dart'; // 引入上面定义的数据库类
    
    const url = String.fromEnvironment("TURSO_URL"); // 远程数据库URL
    const token = String.fromEnvironment("TURSO_TOKEN"); // 认证令牌
    
    late AppDatabase memoryDatabase;
    late AppDatabase localDatabase;
    late AppDatabase remoteDatabase;
    late AppDatabase replicaDatabase;
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      final dir = await getApplicationCacheDirectory(); // 获取应用缓存目录
    
      // 初始化不同类型的数据库实例
      memoryDatabase = AppDatabase(DriftLibsqlDatabase(":memory:")); // 内存数据库
      localDatabase = AppDatabase(DriftLibsqlDatabase("${dir.path}/local.db")); // 本地数据库
      remoteDatabase = AppDatabase(DriftLibsqlDatabase(url, authToken: token)); // 远程数据库
      replicaDatabase = AppDatabase(DriftLibsqlDatabase(
        "${dir.path}/replica.db",
        syncUrl: url,
        authToken: token,
        readYourWrites: true, // 同步写操作
        syncIntervalSeconds: 3, // 每3秒同步一次
      ));
    
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: const Text('Libsql Dart Example')),
            body: Padding(
              padding: const EdgeInsets.all(24),
              child: Builder(builder: (context) {
                return Center(
                  child: Column(
                    children: [
                      FilledButton(
                        onPressed: () {
                          Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => Provider(
                                create: (context) => LibsqlTaskRepository(memoryDatabase),
                                child: const TaskList(),
                              ),
                            ),
                          );
                        },
                        child: const Text("Memory"),
                      ),
                      const SizedBox(height: 16),
                      FilledButton(
                        onPressed: () {
                          Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => Provider(
                                create: (context) => LibsqlTaskRepository(localDatabase),
                                child: const TaskList(),
                              ),
                            ),
                          );
                        },
                        child: const Text("Local"),
                      ),
                      const SizedBox(height: 16),
                      FilledButton(
                        onPressed: () {
                          Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => Provider(
                                create: (context) => LibsqlTaskRepository(remoteDatabase),
                                child: const TaskList(),
                              ),
                            ),
                          );
                        },
                        child: const Text("Remote"),
                      ),
                      const SizedBox(height: 16),
                      FilledButton(
                        onPressed: () {
                          Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => Provider(
                                create: (context) => LibsqlTaskRepository(replicaDatabase),
                                child: const TaskList(),
                              ),
                            ),
                          );
                        },
                        child: const Text("Replica"),
                      ),
                    ],
                  ),
                );
              }),
            ),
          ),
        );
      }
    }
    
  5. 任务列表页面
    创建一个简单的任务列表页面 TaskList,用于展示和管理任务。你可以通过 ProviderTaskRepository 传递给页面,并使用 StreamBuilderFutureBuilder 来显示任务数据:

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'repositories/task_repository.dart';
    
    class TaskList extends StatelessWidget {
      const TaskList({super.key});
    
      @override
      Widget build(BuildContext context) {
        final taskRepository = Provider.of<TaskRepository>(context);
    
        return Scaffold(
          appBar: AppBar(title: const Text('Task List')),
          body: FutureBuilder<List<Task>>(
            future: taskRepository.getAllTasks(), // 获取所有任务
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const Center(child: CircularProgressIndicator());
              } else if (snapshot.hasError) {
                return Center(child: Text('Error: ${snapshot.error}'));
              } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
                return const Center(child: Text('No tasks found'));
              } else {
                return ListView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, index) {
                    final task = snapshot.data![index];
                    return ListTile(
                      title: Text(task.title),
                      subtitle: Text(task.description ?? 'No description'),
                      trailing: Checkbox(
                        value: task.completed,
                        onChanged: (value) {
                          taskRepository.updateTask(
                            TaskTableCompanion(
                              id: Value(task.id),
                              completed: Value(value!),
                            ),
                          );
                        },
                      ),
                      onLongPress: () {
                        taskRepository.deleteTask(task.id); // 删除任务
                      },
                    );
                  },
                );
              }
            },
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () async {
              final newTaskTitle = await _promptForTaskTitle(context);
              if (newTaskTitle != null && newTaskTitle.isNotEmpty) {
                await taskRepository.insertTask(
                  TaskTableCompanion(
                    title: Value(newTaskTitle),
                    description: const Value(null),
                    completed: const Value(false),
                  ),
                );
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('Task added!')),
                );
              }
            },
            child: const Icon(Icons.add),
          ),
        );
      }
    
      Future<String?> _promptForTaskTitle(BuildContext context) async {
        return await showDialog<String>(
          context: context,
          builder: (context) => AlertDialog(
            title: const Text('Add Task'),
            content: TextField(
              decoration: const InputDecoration(hintText: 'Enter task title'),
              autofocus: true,
              onSubmitted: (value) {
                Navigator.of(context).pop(value);
              },
            ),
            actions: [
              TextButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Cancel'),
              ),
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop(
                    (ModalRoute.of(context)?.widget as AlertDialog)
                        .content
                        .key
                        ?.currentContext
                        ?.findRenderObject()
                        ?.debugDescribeChildren()
                        ?.first
                        ?.value as TextEditingController
                        .text,
                  );
                },
                child: const Text('Add'),
              ),
            ],
          ),
        );
      }
    }
    
  6. 任务仓库类
    创建一个 TaskRepository 类来封装与数据库交互的逻辑。你可以根据不同的数据库实例(内存、本地、远程或副本)来选择不同的实现方式:

    import 'package:drift/drift.dart';
    import 'package:drift_libsql_example/database.dart';
    
    class LibsqlTaskRepository implements TaskRepository {
      final AppDatabase _db;
    
      LibsqlTaskRepository(this._db);
    
      @override
      Future<int> insertTask(TaskTableCompanion task) {
        return _db.insertTask(task);
      }
    
      @override
      Future<List<Task>> getAllTasks() {
        return _db.getAllTasks();
      }
    
      @override
      Future<int> updateTask(TaskTableCompanion task) {
        return _db.updateTask(task);
      }
    
      @override
      Future<int> deleteTask(int id) {
        return _db.deleteTask(id);
      }
    }
    
    abstract class TaskRepository {
      Future<int> insertTask(TaskTableCompanion task);
      Future<List<Task>> getAllTasks();
      Future<int> updateTask(TaskTableCompanion task);
      Future<int> deleteTask(int id);
    }
    

更多关于Flutter数据库管理插件drift_libsql的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库管理插件drift_libsql的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用drift_libsql(也称为drift,一个流行的Flutter数据库管理插件)的示例代码。drift是基于SQLite的一个ORM(对象关系映射)库,用于在Flutter应用中方便地管理数据库。

环境设置

首先,确保你的Flutter项目已经创建并配置好。然后,在你的pubspec.yaml文件中添加drift的依赖:

dependencies:
  flutter:
    sdk: flutter
  drift: ^x.y.z  # 请替换为最新版本号
  sqlite3_flutter_libs: ^x.y.z  # drift所需的SQLite原生库

运行flutter pub get来安装这些依赖。

定义数据模型

使用drift的注解来定义你的数据模型。例如,我们定义一个简单的User模型:

import 'package:drift/drift.dart';

part 'user.g.dart';

@DataClassName('User')
class Users extends Table {
  IntColumn get id => integer().autoIncrement().primaryKey()();
  TextColumn get name => text().nullable()();
  TextColumn get email => text().nullable()().withDefault(Constant(''));
}

然后,运行flutter pub run build_runner build来生成数据访问类(UserUsersDao)。

配置数据库

在你的应用中配置数据库连接和迁移:

import 'package:drift/drift.dart';
import 'package:flutter/material.dart';
import 'user.dart';  // 导入自动生成的文件

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Drift Demo'),
        ),
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final DatabaseConnection _db;

  @override
  void initState() {
    super.initState();

    // 配置数据库
    final databases = Databases({
      .platform: (p) async => p.defaultDatabase(),
    });

    // 配置迁移
    final migrations = MigrationSet(
      allMigrations: [
        MigrationStep(
          version: 1,
          migrate: (Database database) async {
            await database.create(users.table);
          },
        ),
      ],
    );

    _db = databases.database(migration: migrations);
  }

  @override
  Widget build(BuildContext context) {
    // 示例:插入数据
    Future<void> insertUser() async {
      final user = User(name: 'Alice', email: 'alice@example.com');
      await _db.into(users).insert(user);
    }

    // 示例:查询数据
    Future<List<User>> queryUsers() async {
      return await _db.query(users).mapToList((row) => row.readTable(users));
    }

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: insertUser,
            child: Text('Insert User'),
          ),
          ElevatedButton(
            onPressed: async () async {
              final users = await queryUsers();
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('Users: ${users.map((user) => user.name).join(', ')}'),
                ),
              );
            },
            child: Text('Query Users'),
          ),
        ],
      ),
    );
  }
}

运行应用

确保你的代码没有错误,然后运行你的Flutter应用。你现在应该能够插入和查询用户数据了。

这个示例展示了如何使用drift库在Flutter应用中管理SQLite数据库,包括定义数据模型、配置数据库连接和迁移、以及执行基本的数据库操作(插入和查询)。根据你的需求,你可以进一步扩展这个示例,添加更多的数据模型和复杂的查询逻辑。

回到顶部