Search code examples
flutterdartpathsqflitemobile-development

Why Deleting Row using sqflite dont work in flutter?


I have problem when deleting row in app it deleting without errors but when fetching for data it still there like it didn't ever deleted I am using sqflite package here is function to get database:

  Future<Database> _getDatabase() async {
    final dbPath = await sql.getDatabasesPath();
    print('get database path');
    final db = await sql.openDatabase(
      path.join(dbPath, 'placesFav.db'),
      onCreate: (db, version) {
        print('creating table');
        return db.execute(
            'CREATE TABLE $_tableName(id TEXT PRIMARY KEY, title TEXT, image TEXT, lat REAL, lng REAL, address TEXT)');
      },
      version: 1,
    );
    return db;
  }

and here is function to fetch data from database:

  Future<void> getPlaces() async {
    final db = await _getDatabase();
    final dataOfDb = await db.query(
      _tableName,
    );
    state = dataOfDb
        .map(
          (row) => FavoritePlace(
            id: row['id'] as String,
            title: row['title'] as String,
            image: File(row['image'] as String),
            favLocation: FavoriteLocation(
              latitude: row['lat'] as double,
              longitude: row['lng'] as double,
              address: row['address'] as String,
            ),
          ),
        )
        .toList();

    await db.close();
  }

And here is delete row function:

Future<void> removePlace(FavoritePlace favPlace) async {
    state = state.where((place) => place.id != favPlace.id).toList();
    final db = await _getDatabase();
    final data =
        await db.delete(_tableName, where: 'id = ?', whereArgs: [favPlace.id]);
    print(data);
    await favPlace.image.delete();
    await db.close();
  }
}

and here is add place function:

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');
    state = [...state, favPlace];
    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();
    print('db closed');
  }

here is where I using it:

class _HomeScreenStateConsumer extends ConsumerState<HomeScreen> {
  List<FavoritePlace> favList = [];
  late Future<void> _loadPlaces;
  AppBar _appBar(BuildContext context) {
    return AppBar(
      actions: [
        IconButton(
          onPressed: () async {
            final favPlace = await Navigator.of(context)
                .push<FavoritePlace>(MaterialPageRoute(builder: (ctx) {
              return const AddNewPlace();
            }));
            if (favPlace == null) {
              return;
            }
          },
          icon: const Icon(Icons.add),
        ),
      ],
      title: const Text('Favorite places'),
    );
  }

  @override
  void initState() {
    _loadPlaces = ref.read(favoritePlaceProvider.notifier).getPlaces();
    super.initState();
  }

  Future<void> _getRefresh() async {
      await ref.read(favoritePlaceProvider.notifier).getPlaces();
  }

  @override
  Widget build(BuildContext context) {
    final height = MediaQuery.of(context).size.height -
        _appBar(context).preferredSize.height -
        MediaQuery.of(context).padding.top;
    favList = ref.watch(favoritePlaceProvider);
    print(favList.length);
    return Scaffold(
      appBar: _appBar(context),
      body: RefreshIndicator(
        onRefresh: _getRefresh,
        triggerMode: RefreshIndicatorTriggerMode.onEdge,
        child: FutureBuilder(
          future: _loadPlaces,
          builder: (context, snapshot) => snapshot.connectionState ==
                  ConnectionState.waiting
              ? const Center(
                  child: CircularProgressIndicator(),
                )
              : favList.isEmpty
                  ? SingleChildScrollView(
            physics: const AlwaysScrollableScrollPhysics(),
                    child: Container(
                      height: height,
                      alignment: Alignment.center,
                      child: Text(
                          'There is no places to see',
                          style: Theme.of(context)
                              .textTheme
                              .titleMedium!
                              .copyWith(
                                color: Colors.white,
                              ),
                        ),
                      ),
                  )
                  : Padding(
                      padding: EdgeInsets.all(8),
                      child: ListView.builder(
                        itemCount: favList.length,
                        itemBuilder: (ctx, index) {
                          print(favList[index].title);
                          return Dismissible(
                              key: ValueKey(favList[index].id),
                              direction: DismissDirection.horizontal,
                              onDismissed: (_) async {
                                setState(() {
                                  ref
                                      .read(favoritePlaceProvider.notifier)
                                      .removePlace(favList[index]);
                                });
                              },
                              child:
                                  FavoriteItem(favPlace: favList[index]));
                        },
                      ),
                    ),
        ),
      ),
    );
  }
}

i was expecting that row deleted but it did in app but when fetching again it appers again and because:

await favPlace.image.delete();

when reloading there is error cuz of image in file deleted

so why this is happing?


Solution

  • Well, the problem is solved. I used the uuid package to create a Universally Unique Identifier for the id. This way, when I make a new item with this uuid it makes it unique. This makes it impossible to get when fetching by get(), so when I use the delete() function to delete it didn't delete it from the database.

    So instead I used DateTime.now().toIso8601String() as the Id, and now it works fine.