【问题标题】:Flutter's sqflite queriesFlutter sqlite 查询
【发布时间】:2020-06-17 12:45:31
【问题描述】:

我正在使用已经存在的数据库 dictionary.db,它有一个表 words 并有 4 列 idenglishWordgermanWordisFavorite

使用 Sqflite,我试图根据英语输入返回德语单词列表,几乎用户流程的工作方式如下:用户输入一个英语单词(例如:“Ability”),然后我返回一个同义词列表德语单词。

我的问题是我不知道该怎么做,我尝试的方法返回完整列表而不是只返回预期的搜索结果

这是我的实体:

class Word {
  final String id;
  final String eng;
  final String ger;
  final String isFav;

  Word({this.id, this.eng, this.ger, this.isFav});

  Map<String, dynamic> toMap() {
    return {
      'wordId': id,
      'englishWord': eng,
      'germanWord': ger,
      'isFavorite': isFav, 
    };
  }

  factory Word.fromMap(Map<String, dynamic> json) => new Word(
    id: json['wordId'],
    eng: json['englishWord'],
    ger: json['germanWord'],
    isFav: json['isFavorite']
  );
}

这是我的数据库助手类:

class DatabaseHelper{
  DatabaseHelper._();
  static final DatabaseHelper databaseHelper = DatabaseHelper._();
  Database _database;

  static const String DB_NAME = "dict.db";
  static const String TABLE = "words";
  static const String ID = "wordId";
  static const String ENGLISH_WORD = "englishWord";
  static const String GERMAN_WORD = "germanWord";
  static const String IS_FAV = "isFavorite";

  Future<Database> get database async {
    if (_database != null) return _database;
    _database = await getDatabaseInstance();
    return _database;
  }

  Future<Database> getDatabaseInstance() async {
    io.Directory directory = await getApplicationDocumentsDirectory();
    String path = join(directory.path, DB_NAME);
    return await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute("CREATE TABLE IF NOT EXISTS $TABLE ("
          "$ID TEXT,"
          "$ENGLISH_WORD TEXT,"
          "$GERMAN_WORD TEXT,"
          "$IS_FAV TEXT"
          ")");
    });
  }

  //This is where I get the search result list
  //I am stuck here I don't know where to go from here, I only get the full list
  Future<List<Word>> searchEnglishResults(String userSearch) async{
    final db = await database;
    var response = await db.query("Word");
    List<Word> list = response.map((c) => Word.fromMap(c)).toList();
    return list;
  }

【问题讨论】:

    标签: flutter dart sqflite


    【解决方案1】:

    我假设数据库如下所示:

    |id     | englidhWord | germanWord        | isFavorite |
    |-------|-------------|-------------------|------------|
    | 'id0' | 'bye'       | 'Tschüss'         | 'false'    |
    | 'id1' | 'bye'       | 'Auf Wiedersehen' | 'true'     |
    

    因此,如果用户搜索“再见”,她/他应该会收到 ['Tschüss', 'Auf Wiedersehen'](Word 模型不仅是德语单词)。

    为此,query 提供了一些选项,例如 wherewhereArgs,您可以使用它们来搜索数据库中的特定行。

    这里我们要在数据库中搜索其englidhWord 字段的值为bye 的行。

    这是您的数据库的编辑版本:

    import 'dart:io';
    
    import 'package:path/path.dart';
    import 'package:sqflite/sqflite.dart';
    import 'package:path_provider/path_provider.dart';
    import 'package:sudoku/src/word.dart';
    
    class DatabaseHelper {
      DatabaseHelper._();
      static final DatabaseHelper databaseHelper = DatabaseHelper._();
      Database _database;
    
      String DB_NAME = "dict.db";
      static const String TABLE = "words";
      static const String ID = "wordId";
      static const String ENGLISH_WORD = "englishWord";
      static const String GERMAN_WORD = "germanWord";
      static const String IS_FAV = "isFavorite";
    
      Future<Database> get database async {
        if (_database != null) return _database;
        _database = await getDatabaseInstance();
        return _database;
      }
    
      Future<Database> getDatabaseInstance() async {
        Directory directory = await getApplicationDocumentsDirectory();
        String path = join(directory.path, DB_NAME);
        return await openDatabase(path, version: 1,
            onCreate: (Database db, int version) async {
          await db.execute("CREATE TABLE IF NOT EXISTS $TABLE ("
              "$ID TEXT,"
              "$ENGLISH_WORD TEXT,"
              "$GERMAN_WORD TEXT,"
              "$IS_FAV TEXT"
              ")");
        });
      }
       //add new words
       Future<int> add(Word word) async {
        final db = await database;
        var response = await db.insert(TABLE, word.toMap());
    
        return response;
      }
    
      //This is where I get the search result list
      //I am stuck here I don't know where to go from here, I only get the full list
      Future<List<Word>> searchEnglishResults(String userSearch) async {
        final db = await database;
        var response = await db
            .query(TABLE, where: '$ENGLISH_WORD = ?', whereArgs: [userSearch]);
        List<Word> list = response.map((c) => Word.fromMap(c)).toList();
        return list;
      }
    }
    
    

    然后我在名为MyApp的页面上使用列表视图显示结果

    import 'package:flutter/material.dart';
    import 'package:sudoku/src/db.dart';
    import 'package:sudoku/src/word.dart';
    
    class MyApp extends StatefulWidget {
      MyApp({Key key}) : super(key: key);
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      DatabaseHelper db;
      @override
      void initState() {
        db = DatabaseHelper.databaseHelper;
        add();
        super.initState();
      }
    
      add() async {
        // await db.add(Word(eng: 'hi', ger: 'Hallo', id: 'id2', isFav: 'true'));
        // await db.add(Word(eng: 'bye', ger: 'Tschüss', id: 'id0', isFav: 'fasle'));
        // await db.add(
        //     Word(eng: 'bye', ger: 'Auf Wiedersehen', id: 'id0', isFav: 'true'));
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: FutureBuilder<List<Word>>(
            future: db.searchEnglishResults('bye'),
            builder: (BuildContext context, AsyncSnapshot<List<Word>> snapshot) {
              if (snapshot.hasData)
                return ListView.builder(
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      title: Text(snapshot.data[index].ger),
                      subtitle: Text(snapshot.data[index].eng),
                      trailing: Text(snapshot.data[index].isFav),
                    );
                  },
                  itemCount: snapshot.data.length,
                );
    
              return Center(
                child: CircularProgressIndicator(),
              );
            },
          ),
        );
      }
    }
    

    我在数据库和 MyApp 的 initState 中包含了一个名为“add”的函数,用于向数据库添加新单词。

    如果您多次刷新应用程序,它会添加重复的行,原因是您应该使DB字段之一唯一,这里可以id这样做,您应该创建如下表:

    return await openDatabase(path, version: 1,
            onCreate: (Database db, int version) async {
          await db.execute("CREATE TABLE IF NOT EXISTS $TABLE ("
              "$ID TEXT NOT NULL PRIMARY KEY,"
              "$ENGLISH_WORD TEXT,"
              "$GERMAN_WORD TEXT,"
              "$IS_FAV TEXT"
              ")");
        });
    
    

    同样在DB的add函数中,你应该选择当它面对重复行时应该做什么(这里是Word),有一些选项,可以替换它,它应该改变如下:

      //add new words
      Future<int> add(Word word) async {
        final db = await database;
        var response = await db.insert(TABLE, word.toMap(), conflictAlgorithm: ConflictAlgorithm.replace);
    
        return response;
      }
    

    我希望这就是你要找的。​​p>

    【讨论】:

    • 这非常有帮助!一个快速的问题,可以使用一次搜索所有内容的查询吗?像这样的东西:var response = await db.query (TABLE, where: "$ENGLISH_WORD or $GERMAN_WORD = ?", whereArgs: [ENGLISH_WORD, GERMAN_WORD]);
    • 很高兴它有帮助。是的,您可以使用几乎所有类型的查询,甚至可以使用joins 之类的东西,也可以使用外键之类的东西。这些函数还有一个raw 版本,用于更复杂的查询。 (rawQuery)
    • 所以我在评论中写的查询是正确的?并且不需要任何调整?
    • 是的,没错,这将搜索条件之一正确的行,正确的形式是` "$ENGLISH_WORD = ? or $GERMAN_WORD = ?" `
    猜你喜欢
    • 2020-10-11
    • 2018-09-03
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多