You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Drift包:能否将查询定义在独立文件或实体模型/仓库中?

模块化CRUD操作的核心解决方案

针对你不想让database.dart因大量CRUD函数臃肿的需求,最常用的两种模式是DAO(数据访问对象)模式和Repository模式,刚好能和你已经拆分表注册文件的思路匹配,实现完全模块化的数据库操作。

1. DAO(数据访问对象)模式:按实体拆分CRUD

每个领域模型对应一个独立的DAO类,把该实体的所有CRUD操作封装在这个类里,database.dart只负责数据库的初始化、表创建和提供数据库连接实例,不再写具体业务查询逻辑。

具体实现步骤:

  • 为每个实体创建单独的目录(比如models/user/),里面包含:
    • 实体的表定义文件(你已经在做的)
    • 对应的DAO类文件
  • DAO类通过构造函数接收Database实例,所有操作都基于这个实例完成。

代码示例:

简化后的database.dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
// 导入所有DAO需要的表定义
import 'models/user/user_table.dart';

class AppDatabase {
  static Database? _database;

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, 'app_database.db');

    return await openDatabase(
      path,
      version: 1,
      onCreate: (db, version) async {
        // 调用各个实体的表创建方法
        await db.execute(createUserTableQuery);
        // 其他表的创建语句...
      },
    );
  }
}
User实体的DAO类(models/user/user_dao.dart)
import 'package:sqflite/sqflite.dart';
import 'user.dart';
import 'user_table.dart';

class UserDao {
  final Database _db;

  UserDao(this._db);

  // 插入用户
  Future<int> insertUser(User user) async {
    return await _db.insert(
      userTableName,
      user.toMap(),
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
  }

  // 获取所有用户
  Future<List<User>> getAllUsers() async {
    final List<Map<String, dynamic>> maps = await _db.query(userTableName);
    return List.generate(maps.length, (i) {
      return User.fromMap(maps[i]);
    });
  }

  // 更新用户
  Future<int> updateUser(User user) async {
    return await _db.update(
      userTableName,
      user.toMap(),
      where: '$userIdColumn = ?',
      whereArgs: [user.id],
    );
  }

  // 删除用户
  Future<int> deleteUser(int id) async {
    return await _db.delete(
      userTableName,
      where: '$userIdColumn = ?',
      whereArgs: [id],
    );
  }

  // 其他自定义查询...
}

2. Repository模式:业务逻辑与数据访问分离

如果你的项目需要处理更复杂的业务逻辑(比如多实体关联查询、数据转换),可以在DAO之上再封装一层Repository类,把业务逻辑和纯数据访问操作分开。Repository可以组合多个DAO的操作,或者负责Model(UI层用的模型)和Entity(数据库层用的实体)之间的转换。

代码示例:UserRepository(models/user/user_repository.dart)

import 'user_dao.dart';
import 'user.dart';
import '../../database.dart';

class UserRepository {
  late final UserDao _userDao;

  UserRepository() {
    // 这里可以用依赖注入框架(比如get_it)来获取Database实例,避免手动传递
    final db = AppDatabase().database;
    db.then((database) => _userDao = UserDao(database));
  }

  // 封装DAO操作,添加业务逻辑
  Future<void> addOrUpdateUser(User user) async {
    // 比如添加前置校验
    if (user.name.isEmpty) throw Exception('用户名不能为空');
    await _userDao.insertUser(user);
  }

  // 直接暴露DAO的查询方法并添加业务过滤
  Future<List<User>> getActiveUsers() async {
    final allUsers = await _userDao.getAllUsers();
    return allUsers.where((user) => user.isActive).toList();
  }
}

3. 依赖注入优化(可选)

如果觉得手动传递Database实例麻烦,可以用依赖注入框架(比如get_it)来管理AppDatabase、DAO和Repository的单例,这样在需要使用的地方直接获取实例即可,不用重复初始化。

总结

  • 用DAO模式拆分每个实体的CRUD,让database.dart回归数据库管理的本职工作
  • 用Repository模式处理业务逻辑,让UI层只和Repository交互,降低耦合
  • 每个实体的表定义、DAO、Repository都放在同一目录下,完全符合模块化开发思路

内容的提问来源于stack exchange,提问作者Jaco van Zyl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:25:54