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
相关产品推荐
相关产品推荐

