Flutter之数据存储Sqflite工具类的使用(记录学习)

这篇文章本来是上周刚学习完就想写的,但是因为工作原因,耽误了,当时想抽个时间专门写这篇文章,写详细一点,到得空写时候突然没思路了,果然还是及时行乐比较好,呸,及时记录。没啥头绪那就简单讲一下吧。

其实关于Sqflite的使用,网上有很多文章也介绍了,而且源码上的注释也很详细,这里就不再说了,不过网上介绍的都仅仅是他的使用,实际开发中,我们需要将这些方法封装成工具类,在百度和GitHub上找了一圈,没有找到有价值的东西,那就自己动手丰衣足食,此工具类是参考Flutter Go项目中数据库的使用完成的,在这里要膜拜一下阿里工程师们,还有世界上所有的程序员们,向他们献上崇高的敬意。Flutter学习,一个项目就够了,废话不多说~~~

本文工具类已上传至Github

 

这是我在学习Sqflite过程中做的笔记,我觉得已经把sqflite的使用概括了,下面来看看工具类的使用:

在main中进行初始化操作

class Provider {
  static Database db;

  // 获取数据库中所有的表
  Future<List> getTables() async {
    if (db == null) {
      return Future.value([]);
    }
    List tables = await db
        .rawQuery('SELECT name FROM sqlite_master WHERE type = "table"');
    List<String> targetList = [];
    tables.forEach((item) {
      targetList.add(item['name']);
    });
    return targetList;
  }

  // 检查数据库中, 表是否完整, 在部份android中, 会出现表丢失的情况
  Future checkTableIsRight() async {
    List<String> expectTables = ['user']; //将项目中使用的表的表名添加集合中

    List<String> tables = await getTables();

    for (int i = 0; i < expectTables.length; i++) {
      if (!tables.contains(expectTables[i])) {
        return false;
      }
    }
    return true;
  }

  //初始化数据库
  Future init() async {
    //Get a location using getDatabasesPath
    String databasesPath = await getDatabasesPath();
    String path = join(databasesPath, 'xxxx.db');
    print(path);
    try {
      db = await openDatabase(path);
    } catch (e) {
      print("Error $e");
    }

    bool tableIsRight = await this.checkTableIsRight();

    if (!tableIsRight) {
      // 关闭上面打开的db,否则无法执行open
      db.close();
      //表不完整
      // Delete the database
      await deleteDatabase(path);

      db = await openDatabase(path, version: 1,
          onCreate: (Database db, int version) async {
        // When creating the db, create the table
        await db.execute(SqlTable.sql_createTable_course);
        await db.execute(SqlTable.sql_createTable_user);

        print('db created version is $version');
      }, onOpen: (Database db) async {
        print('new db opened');
      });
    } else {
      print("Opening existing database");
    }
  }
}

初始化操作很简单,先打开数据库检查表是否完整,如果不完整就关闭数据库并且删除数据库,然后创建一个新的数据库,重新生成表,这里 db.execute(sql) ,需要传入SQL语句,这里我是用创建一个类来管理创建表的SQL语句。

class SqlTable{
  static final String sql_createTable_course = """
    CREATE TABLE course (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    courseId INTEGER NOT NULL UNIQUE, 
    title TEXT NOT NULL, 
    clPublic INTEGER,
    orders INTEGER);
    """;
  static final String sql_createTable_user = """
    CREATE TABLE user (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 
    uid INTEGER NOT NULL UNIQUE, 
    phone TEXT NOT NULL UNIQUE, 
    nickName TEXT,
    portrait TEXT);
    """;
}

初始化完成,进入主题,工具类的使用:

//创建对象,传入表名
var sql = SqlUtil.setTable("user");

增删改查都有两种方式,一种是通过sql语句,另一种是传入表名和数据的方式

查询操作:调用查询的方法,这里的参数是可选的,可以传也可以为空,如果为空就代表查询该表所有数据,将参数以Map集合传入,然后遍历Map集合,讲key和value全部取出,拼接成字符串,这里拼接成的字符串参数就是类似于SQL语句中的条件语句,and也可以更换为or,根据实际情况自己修改,查询到的数据是List集合,当成网络请求解析到实体类里就可以了。

  Future<List<ConfigBean>> _query() async {
    var map = {'phone': '123', 'nickName': '654321'};
    List json = await sql.query(conditions: map);
    if (json.isEmpty) {
      return [];
    }
    //打印一下看看结果
    print('$json');
    //和网络请求数据解析差不多
    List<ConfigBean> config = json.map((json) {
      return new ConfigBean.fromJson(json);
    }).toList();
    return config;
  }


//通过条件查询,可以将表名作为参数传进来,作为公共方法,返回的是一个集合
  Future<List> query({Map<dynamic, dynamic> conditions}) async {
    // 如果传入条件为空,就查询该表全部数据
    if (conditions == null || conditions.isEmpty) {
      return this.get();
    }
    String stringConditions = '';

    int index = 0;
    conditions.forEach((key, value) {
      if (value == null) {
        return ;
      }
      if (value.runtimeType == String) {
        stringConditions = '$stringConditions $key = "$value"';
      }
      if (value.runtimeType == int) {
        stringConditions = '$stringConditions $key = $value';
      }

      if (index >= 0 && index < conditions.length -1) {
        stringConditions = '$stringConditions and';
      }
      index++;
    });
    // print("this is string condition for sql > $stringConditions");
    return await this.querys(tableName, where: stringConditions);
  }


插入操作:

  //插入数据 传入Sql语句和参数 返回插入数据的id
  Future<int> rawInsert(String sql, List arguments) async {
    return await this.db.rawInsert(sql, arguments);
  }

  //插入一条新的数据 返回插入数据的id
  Future<int> insert(Map<String, dynamic> params) async {
    return await this.db.insert(tableName, params);
  }
  
  //示例 插入数据 传入Sql语句和参数 返回插入数据的id
  String sql_insert ='INSERT INTO user(uid, phone, nickName) VALUES(?, ?, ?)';
  List list = [1, '123', 'aaa'];
  sql.rawInsert(sql_insert, list).then((id) {
    setState(() {
      if (id > 0) {
        _result = "数据添加成功";
      } else {
        _result = "数据添加失败";
      }
    });
  });
 //示例 插入数据,传入字段和值以map集合形式
  var map = {'uid': 2, 'phone': account, 'nickName': password};
    sql.insert(map).then((id) {
      setState(() {
        if (id > 0) {
          _result = "数据添加成功";
        } else {
          _result = "数据添加失败";
        }
      });
    });

  //配合网络请求使用

  ///获取所有考试信息
  Future<Null> getCouseList() async {
    Response response = await ApiManager().getCouseList("2");
    var courseBean = CourseBean.fromJson(response.data);
    for (CourseData data in courseBean.data) {
      var map = {
        'courseId': data.courseId,
        'title': data.title,
        'clPublic': data.clPublic,
        'orders': data.order,
      };
      sql.insert(map).then((id){
        if (id >0) {
          print("插入成功$id"); 
         ///**********插入成功进行操作***********///
    
        } else {
          print("插入失败,详情查看日志");
        }
      });
    }
  }

删除操作:

//删除数据 传入Sql语句和参数
  Future<int> rawDelete(String sql, List arguments) async {
    return await this.db.rawDelete(sql, arguments);
  }

  //删除一条或多条数据 单个条件
  Future<int> delete(String key, dynamic value) async {
    return await this.db.delete(tableName, where:'$key = ?', whereArgs:[value]);
  }

  _delete() async {
    //删除数据 传入Sql语句和参数 返回0或1
    String sql_delete = "DELETE FROM user WHERE phone = ?";
    sql.rawDelete(sql_delete, ['123']).then((result) {
      setState(() {
        if (result == 1) {
          _result = "删除成功,请查看";
        } else {
          _result = "删除失败,请看log";
        }
      });
    });
    //删除数据 返回0或1
    sql.delete('phone', '123').then((result) {
      setState(() {
        if (result == 1) {
          _result = "删除成功,请查看";
        } else {
          _result = "删除失败,请看log";
        }
      });
    });
  }

修改操作

  //修改数据 传入Sql语句和参数
  Future<int> rawUpdate(String sql, List arguments) async {
    return await this.db.rawUpdate(sql, arguments);
  }

  //修改一条或多条数据 单个条件
  Future<int> update(Map<String, dynamic> params, String key, dynamic value) async {
    return await this.db.update(tableName, params, where:'$key = ?', whereArgs:[value]);
  }

  _update() async {
    //修改数据 传入Sql语句和参数 返回0或1
    String sql_update = "UPDATE user SET phone = ? WHERE nickName = ?";
    sql.rawUpdate(sql_update, ["123", 'aaa']).then((result) {
      setState(() {
        if (result == 1) {
          _result = "修改成功,请查看";
        } else {
          _result = "修改失败,请看log";
        }
      });
    });
    //修改数据 返回0或1
    var map = {'phone': '654321', 'nickName': 'flutter'};
    sql.update(map, 'phone', '123').then((result) {
      setState(() {
        if (result == 1) {
          _result = "修改成功,请查看";
        } else {
          _result = "修改失败,请看log";
        }
      });
    });
  }

上面的这些增删改查方法中, tableName就是我们在new对象的时候传入的表名,如果你想把表名作为参数传入方法中,以更加灵活的话,稍微修改一下工具类即可。

贴上完整代码

/**
 * Created by yangqc on 2019-04-10
 * 数据库工具类
 */
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'provider.dart';

class BaseModel {
  Database db;
  final String table = '';
  var querys;

  BaseModel(this.db) {
    querys = db.query;
  }
}

class SqlUtil extends BaseModel {
  final String tableName;

  SqlUtil.setTable(String name)
      : tableName = name,
        super(Provider.db);

  //查询该表中的所有数据
  Future<List> get() async {
    return await this.querys(tableName);
  }

  //插入数据 传入Sql语句和参数 返回插入数据的id
  Future<int> rawInsert(String sql, List arguments) async {
    return await this.db.rawInsert(sql, arguments);
  }

  //插入一条新的数据 返回插入数据的id
  Future<int> insert(Map<String, dynamic> params) async {
    return await this.db.insert(tableName, params);
  }

  //删除数据 传入Sql语句和参数
  Future<int> rawDelete(String sql, List arguments) async {
    return await this.db.rawDelete(sql, arguments);
  }

  //删除一条或多条数据 单个条件
  Future<int> delete(String key, dynamic value) async {
    return await this.db.delete(tableName, where:'$key = ?', whereArgs:[value]);
  }

  //删除一条或多条数据 多个条件
  Future<int> deletes(Map<String, dynamic> conditions, String ao) async {
    String stringConditions = '';

    int index = 0;
    if (ao == '') ao = 'and';
    conditions.forEach((key, value) {
      if (value == null) {
        return ;
      }
      if (value.runtimeType == String) {
        stringConditions = '$stringConditions $key = "$value"';
      }
      if (value.runtimeType == int) {
        stringConditions = '$stringConditions $key = $value';
      }

      if (index >= 0 && index < conditions.length -1) {
        stringConditions = '$stringConditions $ao';
      }
      index++;
    });
    return await this.db.delete(tableName, where:stringConditions);
  }

  //修改数据 传入Sql语句和参数
  Future<int> rawUpdate(String sql, List arguments) async {
    return await this.db.rawUpdate(sql, arguments);
  }

  //修改一条或多条数据 单个条件
  Future<int> update(Map<String, dynamic> params, String key, dynamic value) async {
    return await this.db.update(tableName, params, where:'$key = ?', whereArgs:[value]);
  }

  //修改一条或多条数据 多个条件
  Future<int> updates(Map<String, dynamic> params, Map<String, dynamic> conditions, String ao) async {
    String stringConditions = '';

    int index = 0;
    if (ao == '') ao = 'and';
    conditions.forEach((key, value) {
      if (value == null) {
        return ;
      }
      if (value.runtimeType == String) {
        stringConditions = '$stringConditions $key = "$value"';
      }
      if (value.runtimeType == int) {
        stringConditions = '$stringConditions $key = $value';
      }

      if (index >= 0 && index < conditions.length -1) {
        stringConditions = '$stringConditions $ao';
      }
      index++;
    });
    return await this.db.update(tableName, params, where:stringConditions);
  }

  //查询数据 传入Sql语句和参数
  Future<List> rawQuery(String sql, List arguments) async {
    return await this.db.rawQuery(sql, arguments);
  }

  //通过条件查询,可以将表名作为参数传进来,作为公共方法,返回的是一个集合
  Future<List> query({Map<dynamic, dynamic> conditions}) async {
    // 如果传入条件为空,就查询该表全部数据
    if (conditions == null || conditions.isEmpty) {
      return this.get();
    }
    String stringConditions = '';

    int index = 0;
    conditions.forEach((key, value) {
      if (value == null) {
        return ;
      }
      if (value.runtimeType == String) {
        stringConditions = '$stringConditions $key = "$value"';
      }
      if (value.runtimeType == int) {
        stringConditions = '$stringConditions $key = $value';
      }

      if (index >= 0 && index < conditions.length -1) {
        stringConditions = '$stringConditions and';
      }
      index++;
    });
    // print("this is string condition for sql > $stringConditions");
    return await this.querys(tableName, where: stringConditions);
  }
}


如果这篇文章对你有帮助,那就点个赞吧~

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值