这篇文章本来是上周刚学习完就想写的,但是因为工作原因,耽误了,当时想抽个时间专门写这篇文章,写详细一点,到得空写时候突然没思路了,果然还是及时行乐比较好,呸,及时记录。没啥头绪那就简单讲一下吧。
其实关于Sqflite的使用,网上有很多文章也介绍了,而且源码上的注释也很详细,这里就不再说了,不过网上介绍的都仅仅是他的使用,实际开发中,我们需要将这些方法封装成工具类,在百度和GitHub上找了一圈,没有找到有价值的东西,那就自己动手丰衣足食,此工具类是参考Flutter Go项目中数据库的使用完成的,在这里要膜拜一下阿里工程师们,还有世界上所有的程序员们,向他们献上崇高的敬意。Flutter学习,一个项目就够了,废话不多说~~~
本文工具类已上传至Github
这是我在学习Sqflite过程中做的笔记,我觉得已经把sqflite的使用概括了,下面来看看工具类的使用:
在main中进行初始化操作
class Provider {
static Database db;
// 获取数据库中所有的表
Future getTables() async {
if (db == null) {
return Future.value([]);
}
List tables = await db
.rawQuery('SELECT name FROM sqlite_master WHERE type = "table"');
List targetList = [];
tables.forEach((item) {
targetList.add(item['name']);
});
return targetList;
}
// 检查数据库中, 表是否完整, 在部份android中, 会出现表丢失的情况
Future checkTableIsRight() async {
List expectTables = ['user']; //将项目中使用的表的表名添加集合中
List 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> _query() async {
var map = {'phone': '123', 'nickName': '654321'};
List json = await sql.query(conditions: map);
if (json.isEmpty) {
return [];
}
//打印一下看看结果
print('$json');
//和网络请求数据解析差不多
List config = json.map((json) {
return new ConfigBean.fromJson(json);
}).toList();
return config;
}
//通过条件查询,可以将表名作为参数传进来,作为公共方法,返回的是一个集合
Future query({Map 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 rawInsert(String sql, List arguments) async {
return await this.db.rawInsert(sql, arguments);
}
//插入一条新的数据 返回插入数据的id
Future insert(Map 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 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 rawDelete(String sql, List arguments) async {
return await this.db.rawDelete(sql, arguments);
}
//删除一条或多条数据 单个条件
Future 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 rawUpdate(String sql, List arguments) async {
return await this.db.rawUpdate(sql, arguments);
}
//修改一条或多条数据 单个条件
Future update(Map 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 get() async {
return await this.querys(tableName);
}
//插入数据 传入Sql语句和参数 返回插入数据的id
Future rawInsert(String sql, List arguments) async {
return await this.db.rawInsert(sql, arguments);
}
//插入一条新的数据 返回插入数据的id
Future insert(Map params) async {
return await this.db.insert(tableName, params);
}
//删除数据 传入Sql语句和参数
Future rawDelete(String sql, List arguments) async {
return await this.db.rawDelete(sql, arguments);
}
//删除一条或多条数据 单个条件
Future delete(String key, dynamic value) async {
return await this.db.delete(tableName, where:'$key = ?', whereArgs:[value]);
}
//删除一条或多条数据 多个条件
Future deletes(Map 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 rawUpdate(String sql, List arguments) async {
return await this.db.rawUpdate(sql, arguments);
}
//修改一条或多条数据 单个条件
Future update(Map params, String key, dynamic value) async {
return await this.db.update(tableName, params, where:'$key = ?', whereArgs:[value]);
}
//修改一条或多条数据 多个条件
Future updates(Map params, Map 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 rawQuery(String sql, List arguments) async {
return await this.db.rawQuery(sql, arguments);
}
//通过条件查询,可以将表名作为参数传进来,作为公共方法,返回的是一个集合
Future query({Map 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);
}
}
如果这篇文章对你有帮助,那就点个赞吧~