从Flutter App的资产中导入SQFlite数据库,并使用RawQuery显示特定行

发布于 2025-02-11 18:48:03 字数 4869 浏览 4 评论 0原文

我已经构建了一个使用颤音的应用程序。其功能的一部分是,用户可以搜索应用程序资产区域中的数据。该数据最初是以JSON格式的,尽管我已将其转换为SQLite数据库以节省存储空间。这实际上帮助我节省了约90%,这很棒。问题是,搜索委托不再有效。它只是返回一个空列表,尽管控制台中没有产生错误。

我创建了一个模型类,以帮助从SQLite数据库表中读取数据,该数据看起来像这样:

/// Class to handle the country data in the database
class CountriesDB {
  /// Defining the variables to be pulled from the json file
  late int id;
  late String continent;
  late String continentISO;
  late String country;
  late String countryISO;
  late String flagIconLocation;

  CountriesDB({
    required this.id,
    required this.continent,
    required this.continentISO,
    required this.country,
    required this.countryISO,
    required this.flagIconLocation,
  });

  CountriesDB.fromMap(dynamic obj) {
    this.id = obj[id];
    this.continent = obj[continent];
    this.continentISO = obj[continentISO];
    this.country = obj[country];
    this.countryISO = obj[countryISO];
    this.flagIconLocation = obj[flagIconLocation];
  }

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      'id': id,
      'continent': continent,
      'continentISO': continentISO,
      'country': country,
      'countryISO': countryISO,
      'flagIconLocation': flagIconLocation,
    };
    return map;
  }
}

据我所知,读取存储在应用程序资产文件夹中的数据库中的数据,我需要从编程中进行程序上将其转换为工作数据库。我已经编写了以下代码,以对:

  /// Creating the database values
  static final DatabaseClientData instance = DatabaseClientData._init();
  static Database? _database;
  DatabaseClientData._init();

  /// Calling the database
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('databaseWorking.db');
    return _database!;
  }

  /// Future function to open the database
  Future<Database> _initDB(String filePath) async {
    /// Getting the data from the database in 'assets'
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, filePath);

    /// Check if the database exists
    var exists = await databaseExists(path);

    if (!exists) {
      /// Should happen only the first time the application is launched
      print('Creating new copy from asset');

      /// Make sure the parent directory exists
      try {
        await Directory(dirname(path)).create(recursive: true);
      } catch (_) {}

      /// Copy from the asset
      ByteData data =
          await rootBundle.load('assets/data/database.db');
      List<int> bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

      /// Write and flush the bytes written
      await File(path).writeAsBytes(bytes, flush: true);
    } else {
      print('Opening existing database');
    }
    return await openDatabase(path, readOnly: true);
  }

我所做的下一件事是创建一个未来的函数,该功能使用rawQuery来搜索数据库。为此,代码是:

  /// Functions to search for specific database entries
  /// Countries
  static Future<List<CountriesDB>> searchCountries(String keyword) async {
    final db = await instance.database;
    List<Map<String, dynamic>> allCountries = await db.rawQuery(
        'SELECT * FROM availableISOCountries WHERE continent=? OR continentISO=? OR country=? OR countryISO=?',
        ['%keyword%']);
    List<CountriesDB> countries =
        allCountries.map((country) => CountriesDB.fromMap(country)).toList();
    return countries;
  }

最后,我使用的是Flutter Search代表类,允许用户与数据库进行交互并搜索特定的行。这是我为此构建的小部件:

  /// Checks to see if suggestions can be made and returns error if not
  Widget buildSuggestions(BuildContext context) => Container(
        color: Color(0xFFF7F7F7),
        child: FutureBuilder<List<CountriesDB>>(
          future: DatabaseClientData.searchCountries(query),
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                return Center(
                    child: PlatformCircularProgressIndicator(
                  material: (_, __) => MaterialProgressIndicatorData(
                    color: Color(0xFF287AD3),
                  ),
                  cupertino: (_, __) => CupertinoProgressIndicatorData(),
                ));
              default:
                if (query.isEmpty) {
                  return buildAllSuggestionsNoSearch(snapshot.data!);
                } else if (snapshot.hasError || snapshot.data!.isEmpty) {
                  return buildNoSuggestionsError(context);
                } else {
                  return buildSuggestionsSuccess(snapshot.data!);
                }
            }
          },
        ),
      );

想法是,我构建的功能将在用户搜索之前返回整个列表,并且一旦用户开始键入,只会显示任何与搜索查询匹配的行。当我使用JSON数据时,这很好,但是它正在返回一个空列表,但控制台中没有任何错误。这使得很难知道我的代码在哪里出错。

我的代码在哪里出了问题,以至于它没有返回任何数据?我该如何纠正?谢谢!

I've built an app using Flutter. Part of its functionality is that users can search through data which is in the assets area of the app. This data was originally in JSON format, although I have converted it into an SQLite database to save storage space. That has actually helped me to save around 90%, which is great. The problem is, the search delegate no longer works. It simply returns an empty list, although no errors are produced in the console.

I have created a model class to help read the data from the SQLite database table, which looks like this:

/// Class to handle the country data in the database
class CountriesDB {
  /// Defining the variables to be pulled from the json file
  late int id;
  late String continent;
  late String continentISO;
  late String country;
  late String countryISO;
  late String flagIconLocation;

  CountriesDB({
    required this.id,
    required this.continent,
    required this.continentISO,
    required this.country,
    required this.countryISO,
    required this.flagIconLocation,
  });

  CountriesDB.fromMap(dynamic obj) {
    this.id = obj[id];
    this.continent = obj[continent];
    this.continentISO = obj[continentISO];
    this.country = obj[country];
    this.countryISO = obj[countryISO];
    this.flagIconLocation = obj[flagIconLocation];
  }

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      'id': id,
      'continent': continent,
      'continentISO': continentISO,
      'country': country,
      'countryISO': countryISO,
      'flagIconLocation': flagIconLocation,
    };
    return map;
  }
}

As far as I am aware, to read data in a database that is stored within the assets folder of the app, I need to programatically convert it into a working database. I have written the following code, to sort that:

  /// Creating the database values
  static final DatabaseClientData instance = DatabaseClientData._init();
  static Database? _database;
  DatabaseClientData._init();

  /// Calling the database
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('databaseWorking.db');
    return _database!;
  }

  /// Future function to open the database
  Future<Database> _initDB(String filePath) async {
    /// Getting the data from the database in 'assets'
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, filePath);

    /// Check if the database exists
    var exists = await databaseExists(path);

    if (!exists) {
      /// Should happen only the first time the application is launched
      print('Creating new copy from asset');

      /// Make sure the parent directory exists
      try {
        await Directory(dirname(path)).create(recursive: true);
      } catch (_) {}

      /// Copy from the asset
      ByteData data =
          await rootBundle.load('assets/data/database.db');
      List<int> bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

      /// Write and flush the bytes written
      await File(path).writeAsBytes(bytes, flush: true);
    } else {
      print('Opening existing database');
    }
    return await openDatabase(path, readOnly: true);
  }

The next thing I have done is to create a Future function that searches the database using a rawQuery. The code for this is:

  /// Functions to search for specific database entries
  /// Countries
  static Future<List<CountriesDB>> searchCountries(String keyword) async {
    final db = await instance.database;
    List<Map<String, dynamic>> allCountries = await db.rawQuery(
        'SELECT * FROM availableISOCountries WHERE continent=? OR continentISO=? OR country=? OR countryISO=?',
        ['%keyword%']);
    List<CountriesDB> countries =
        allCountries.map((country) => CountriesDB.fromMap(country)).toList();
    return countries;
  }

Finally, I am using the Flutter Search Delegate class to allow the user to interact with the database and search for specific rows. This is the widget I have built for that:

  /// Checks to see if suggestions can be made and returns error if not
  Widget buildSuggestions(BuildContext context) => Container(
        color: Color(0xFFF7F7F7),
        child: FutureBuilder<List<CountriesDB>>(
          future: DatabaseClientData.searchCountries(query),
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                return Center(
                    child: PlatformCircularProgressIndicator(
                  material: (_, __) => MaterialProgressIndicatorData(
                    color: Color(0xFF287AD3),
                  ),
                  cupertino: (_, __) => CupertinoProgressIndicatorData(),
                ));
              default:
                if (query.isEmpty) {
                  return buildAllSuggestionsNoSearch(snapshot.data!);
                } else if (snapshot.hasError || snapshot.data!.isEmpty) {
                  return buildNoSuggestionsError(context);
                } else {
                  return buildSuggestionsSuccess(snapshot.data!);
                }
            }
          },
        ),
      );

The idea is that the functionality I have built will return the whole list before a user searches and once a users starts typing, they will only be shown any rows that match their search query. This worked fine when I was using JSON data but it is returning an empty list, yet there are no errors printed in the console, at all. That makes it quite hard to know where my code is going wrong.

Where have I gone wrong with my code, such that it is not returning any data? How can I correct this? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文