Flutter 使用 sqflite 如何防止删除存在关联数据的分组表记录
实现方案
方案1:应用层逻辑校验(无需修改表结构,快速实现)
你当前的deleteGroups方法逻辑写反了,现在是查询到关联item时反而执行删除,无关联时无返回值,修正如下:
Future<int> deleteGroups(int id) async { var dbClient = await db; // 查询是否有关联的item记录,group是SQL关键字需加反引号 List<Map> items = await dbClient.query("item", where: '`group` = ?', whereArgs: [id]); if (items.isNotEmpty) { // 存在关联数据,返回自定义错误码,-1代表禁止删除 return -1; } else { // 无关联数据,执行删除 return await dbClient.delete("group", where: 'id = ?', whereArgs: [id]); } }
你在UI层调用删除分组接口时,判断返回值即可:
- 返回-1:弹出提示「当前分组已被商品关联,无法删除」
- 返回1:删除成功
- 返回0:无对应分组记录
方案2:数据库外键约束(更严谨,从底层阻止非法删除)
SQLite支持外键约束,开启后可以从数据库层面保证数据一致性,不需要每次业务层重复写校验逻辑,修改步骤如下:
- 开启数据库外键支持,修改
initDb方法,增加onConfigure回调,同时升级数据库版本号:
initDb() async { io.Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, DB_NAME); var db = await openDatabase( path, version: 2, // 表结构修改,版本号+1 onCreate: _onCreate, onUpgrade: _onUpgrade, // 开启外键支持 onConfigure: (Database db) async { await db.execute('PRAGMA foreign_keys = ON'); }, ); return db; }
- 修改建表逻辑,修正字段类型不匹配问题,增加外键约束:
你当前item表的group字段类型是TEXT,和group表的INTEGER类型id不匹配,需要同步修正,同时增加外键约束限制删除:
_onCreate(Database db, int version) async { await db.execute(""" CREATE TABLE 'group' ( 'id' INTEGER PRIMARY KEY, 'code' TEXT, 'description' TEXT ) """); await db.execute(""" CREATE TABLE 'category' ( 'id' INTEGER PRIMARY KEY, 'code' TEXT, 'description' TEXT ) """); await db.execute(""" CREATE TABLE 'item' ( 'id' INTEGER PRIMARY KEY, 'code' TEXT, 'description' TEXT, 'cost' REAL, 'price' REAL, 'category' INTEGER, 'group' INTEGER, -- 外键约束,关联group表id,删除时限制 FOREIGN KEY ('group') REFERENCES 'group'(id) ON DELETE RESTRICT, FOREIGN KEY ('category') REFERENCES 'category'(id) ON DELETE RESTRICT ) """); }
- 增加
onUpgrade逻辑处理版本升级(开发阶段可以直接卸载App重装跳过这步,线上环境需要写迁移逻辑):
_onUpgrade(Database db, int oldVersion, int newVersion) async { if (oldVersion < 2) { // 示例:删除旧表重新创建,生产环境建议做数据迁移 await db.execute("DROP TABLE IF EXISTS item"); await db.execute("DROP TABLE IF EXISTS 'group'"); await db.execute("DROP TABLE IF EXISTS category"); await _onCreate(db, newVersion); } }
- 捕获外键约束异常处理删除逻辑:
Future<int> deleteGroups(int id) async { var dbClient = await db; try { return await dbClient.delete("group", where: 'id = ?', whereArgs: [id]); } catch (e) { // 外键约束触发,存在关联数据无法删除,返回错误码 return -1; } }
内容的提问来源于stack exchange,提问作者Jian Yuan Ng
相关产品推荐
相关产品推荐

