简体   繁体   English

如何在Flutter中使用SQFlite进行数据库查询

[英]How to do a database query with SQFlite in Flutter

How do you query data from SQLite database in Flutter using the SQFlite plugin? 如何使用SQFlite插件在Flutter中查询来自SQLite数据库的数据?

I have been working on learning this recently, so I am adding my answer below as a means to help me learn and also as a quick reference for others in the future. 我最近一直在努力学习这个,所以我在下面添加我的答案作为一种帮助我学习的方法,并且作为未来其他人的快速参考。

Add the dependencies 添加依赖项

Open pubspec.yaml and in the dependencies section add the following lines: 打开pubspec.yaml并在依赖项部分中添加以下行:

sqflite: ^1.0.0
path_provider: ^0.4.1

The sqflite is the SQFlite plugin of course and the path_provider will help us get the user directory on Android and iPhone. sqflite当然是SQFlite插件, path_provider将帮助我们获取Android和iPhone上的用户目录。 You can check the most up-to-date version numbers here: sqflite and path_provider . 您可以在此处查看最新版本号: sqflitepath_provider

Make a database helper class 创建一个数据库助手类

I'm keeping a global reference to the database in a singleton class. 我在单例类中保留了对数据库的全局引用。 This will prevent concurrency issues and data leaks. 这将防止并发问题和数据泄漏。 You can also add helper methods (like query) in here for accessing the database. 您还可以在此处添加辅助方法(如查询)以访问数据库。

Create a new file called database_helper.dart and paste in the following code: 创建一个名为database_helper.dart的新文件并粘贴以下代码:

import 'dart:io' show Directory;
import 'package:path/path.dart' show join;
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart' show getApplicationDocumentsDirectory;

class DatabaseHelper {

  static final _databaseName = "MyDatabase.db";
  static final _databaseVersion = 1;

  static final table = 'my_table';

  static final columnId = '_id';
  static final columnName = 'name';
  static final columnAge = 'age';

  // make this a singleton class
  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  // only have a single app-wide reference to the database
  static Database _database;
  Future<Database> get database async {
    if (_database != null) return _database;
    // lazily instantiate the db the first time it is accessed
    _database = await _initDatabase();
    return _database;
  }

  // this opens the database (and creates it if it doesn't exist)
  _initDatabase() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, _databaseName);
    return await openDatabase(path,
        version: _databaseVersion,
        onCreate: _onCreate);
  }

  // SQL code to create the database table
  Future _onCreate(Database db, int version) async {
    await db.execute('''
          CREATE TABLE $table (
            $columnId INTEGER PRIMARY KEY,
            $columnName TEXT NOT NULL,
            $columnAge INTEGER NOT NULL
          )
          ''');

    // prepopulate a few rows (consider using a transaction)
    await db.rawInsert('INSERT INTO $table ($columnName, $columnAge) VALUES("Bob", 23)');
    await db.rawInsert('INSERT INTO $table ($columnName, $columnAge) VALUES("Mary", 32)');
    await db.rawInsert('INSERT INTO $table ($columnName, $columnAge) VALUES("Susan", 12)');
  }
}

Note that when the database is created I pre-populated a few rows. 请注意,在创建数据库时,我预先填充了几行。 This is so that we have something to work with in the query examples below. 这样我们就可以在下面的查询示例中使用。

Query data 查询数据

We'll use an async method to do our query because database operations can be expensive. 我们将使用异步方法来执行查询,因为数据库操作可能很昂贵。

Get all rows 获取所有行

To do a SELECT * and return everything in the table you just pass in the table name. 要执行SELECT *并返回表中的所有内容,只需传入表名即可。

  _query() async {

    // get a reference to the database
    Database db = await DatabaseHelper.instance.database;

    // get all rows
    List<Map> result = await db.query(DatabaseHelper.table);

    // print the results
    result.forEach((row) => print(row));
    // {_id: 1, name: Bob, age: 23}
    // {_id: 2, name: Mary, age: 32}
    // {_id: 3, name: Susan, age: 12}
  }

Get a single row 获得一行

We can pass an argument in for the where parameter to select specific rows that meet our criteria. 我们可以为where参数传递一个参数,以选择符合我们条件的特定行。 In this example we will query the row with an ID of 1 . 在此示例中,我们将查询ID为1的行。

  _query() async {

    // get a reference to the database
    Database db = await DatabaseHelper.instance.database;

    // get single row
    List<String> columnsToSelect = [
      DatabaseHelper.columnId,
      DatabaseHelper.columnName,
      DatabaseHelper.columnAge,
    ];
    String whereString = '${DatabaseHelper.columnId} = ?';
    int rowId = 1;
    List<dynamic> whereArguments = [rowId];
    List<Map> result = await db.query(
        DatabaseHelper.table,
        columns: columnsToSelect,
        where: whereString,
        whereArgs: whereArguments);

    // print the results
    result.forEach((row) => print(row));
    // {_id: 1, name: Bob, age: 23}
  }

The items in the whereArguments list get substituted in place of the ? whereArguments列表中的项目取代了? s in the whereString . whereString In this case there was only one ? 在这种情况下,只有一个? so the whereArguments only had one item. 所以whereArguments只有一个项目。 If there were two ? 如果有两个? s (for example an integer and a string), then you would have two items in the list. s(例如一个整数和一个字符串),那么你将在列表中有两个项目。

Raw query 原始查询

If you prefer the familiarity or flexibility of SQL code itself, you can do a raw query. 如果您更喜欢SQL代码本身的熟悉性或灵活性,则可以执行原始查询。 In this example we will select any row whose name column is 'Mary' . 在此示例中,我们将选择name列为'Mary'任何行。

  _query() async {

    // get a reference to the database
    Database db = await DatabaseHelper.instance.database;

    // raw query
    List<Map> result = await db.rawQuery('SELECT * FROM my_table WHERE name=?', ['Mary']);

    // print the results
    result.forEach((row) => print(row));
    // {_id: 2, name: Mary, age: 32}
  }

Be sure to use data binding using ? 一定要使用数据绑定? string replacements. 字符串替换。 This will guard against SQL injection attacks. 这将防止SQL注入攻击。

Notes 笔记

  • You will have to import the DatabaseHelper class and sqflite if you are in another file (like main.dart). 如果您在另一个文件(如main.dart)中,则必须导入DatabaseHelper类和sqflite
  • The SQFlite plugin uses a Map<String, dynamic> to map the column names to the data in each row. SQFlite插件使用Map<String, dynamic>将列名映射到每行中的数据。

Supplemental code 补充代码

在此输入图像描述

For your copy-and-paste convenience, here is the layout code for main.dart : 为了方便您的复制和粘贴,这里是main.dart的布局代码:

import 'package:flutter/material.dart';
// I called my project 'flutter_database_operations'. You can update for yours.
import 'package:flutter_database_operations/database_helper.dart';
import 'package:sqflite/sqflite.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SQFlite Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('sqflite'),
      ),
      body: RaisedButton(
        child: Text('query', style: TextStyle(fontSize: 20),),
        onPressed: () {_query();},
      ),
    );
  }

  _query() async {

    // get a reference to the database
    Database db = await DatabaseHelper.instance.database;

    // get all rows
    List<Map> result = await db.query(DatabaseHelper.table);

    // get single row
    //List<Map> result = await db.query(DatabaseHelper.table,
    //    columns: [DatabaseHelper.columnId, DatabaseHelper.columnName, DatabaseHelper.columnAge],
    //    where: '${DatabaseHelper.columnId} = ?',
    //    whereArgs: [1]);


    // raw query
    //List<Map> result = await db.rawQuery('SELECT * FROM my_table WHERE name=?', ['Mary']);

    // get each row in the result list and print it
    result.forEach((row) => print(row));
  }
}

Going on 继续

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM