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

Flutter中sqflite删除数据行无效问题求助

解决Flutter中sqflite删除数据不生效及图片删除后加载报错问题

问题现象

  • 使用sqflite删除数据行无报错,但重新获取数据时该行仍存在
  • 执行await favPlace.image.delete()后,重新加载页面因图片文件已删除出现报错

修复方案

一、解决数据库删除不生效问题

问题根源:removePlace中先更新本地state再执行数据库删除,若数据库操作未成功(或未完成),本地状态临时更新,但重新拉取数据时会从数据库恢复旧数据;同时缺少错误捕获,无法排查删除失败原因。

修改removePlace函数:

Future<void> removePlace(FavoritePlace favPlace) async {
  final db = await _getDatabase();
  try {
    // 先执行数据库删除,确保数据持久化层先更新
    final deletedCount = await db.delete(
      _tableName,
      where: 'id = ?',
      whereArgs: [favPlace.id],
    );
    print('Deleted rows count: $deletedCount');
    
    // 仅当数据库删除成功(影响行数>0)时,再更新本地状态
    if (deletedCount > 0) {
      state = state.where((place) => place.id != favPlace.id).toList();
      // 图片删除放在状态更新后,避免UI还未更新就丢失图片导致异常
      await favPlace.image.delete();
    }
  } catch (e) {
    print('Delete operation failed: $e');
    // 可根据需求添加用户可见的错误提示
  } finally {
    await db.close();
  }
}

二、解决图片删除后加载报错问题

问题根源:数据库中仍保留已删除图片的路径,getPlaces直接根据路径创建File对象,加载时因文件不存在触发报错。

修改getPlaces函数:

Future<void> getPlaces() async {
  final db = await _getDatabase();
  final dataOfDb = await db.query(_tableName);
  
  final validPlaces = <FavoritePlace>[];
  final invalidIds = <String>[];

  for (final row in dataOfDb) {
    final imagePath = row['image'] as String;
    final imageFile = File(imagePath);
    
    // 检查图片文件是否存在,仅保留有效数据
    if (await imageFile.exists()) {
      validPlaces.add(FavoritePlace(
        id: row['id'] as String,
        title: row['title'] as String,
        image: imageFile,
        favLocation: FavoriteLocation(
          latitude: row['lat'] as double,
          longitude: row['lng'] as double,
          address: row['address'] as String,
        ),
      ));
    } else {
      // 记录无效数据ID,后续清理数据库
      invalidIds.add(row['id'] as String);
    }
  }

  // 清理数据库中的无效数据
  if (invalidIds.isNotEmpty) {
    await db.delete(
      _tableName,
      where: 'id IN (${List.filled(invalidIds.length, '?').join(',')})',
      whereArgs: invalidIds,
    );
  }

  state = validPlaces;
  await db.close();
}

三、页面代码优化

问题:onDismissed中调用异步的removePlace但未等待完成,且多余的setState会导致不必要的UI重建。

修改onDismissed回调:

onDismissed: (_) async {
  await ref.read(favoritePlaceProvider.notifier).removePlace(favList[index]);
  // 移除setState,Riverpod会自动监听state变化更新UI
},

额外优化addPlace函数:
当前addPlace返回类型为void但内部使用async,改为Future<void>确保调用方可等待操作完成,同时调整状态更新顺序,保证数据一致性:

Future<void> addPlace(FavoritePlace favPlace) async {
  final appDir = await app_path.getApplicationDocumentsDirectory();
  final imageName = path.basename(favPlace.image.path);
  final cImage = await favPlace.image.copy('${appDir.path}/${favPlace.id[3]}$imageName');
  
  final db = await _getDatabase();
  await db.insert(_tableName, {
    'id': favPlace.id,
    'title': favPlace.title,
    'image': cImage.path,
    'lat': favPlace.favLocation.latitude,
    'lng': favPlace.favLocation.longitude,
    'address': favPlace.favLocation.address,
  });
  await db.close();
  
  // 数据库操作完成后再更新本地状态
  state = [...state, favPlace.copyWith(image: cImage)];
  print('db closed');
}

内容的提问来源于stack exchange,提问作者Talat Saleh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:10:22