Flutter数据访问插件dart_data_source的使用
Flutter数据访问插件dart_data_source的使用
dart_data_source
是一个基于 Sqflite
的 Dart 数据访问层。它可以帮助你在 Flutter 应用中更方便地操作 SQLite 数据库。
安装插件
首先,在你的 pubspec.yaml
文件中添加 dart_data_source
依赖:
dependencies:
dart_data_source: ^最新版本号
然后运行 flutter pub get
来安装依赖。
使用步骤
使用 dart_data_source
插件通常包括以下三个步骤:
- 扩展
DatabaseModel
类 - 初始化数据库
- 执行 SQL 操作
1. 扩展 DatabaseModel
类
创建一个继承自 DatabaseModel
的类,并在其中定义表结构、字段等。
import 'package:dart_data_source/dart_data_source.dart';
class DbModel extends DatabaseModel {
// grade
late StringColumn gradeName;
late IntColumn studentsCount;
late Table gradesTable;
// student
late DbColumn studentName;
late IntColumn studentDegree;
late Table studentsTable;
late IntColumn studentGradeFk;
// indices
late Index gradeNameIndex;
late Index studentNameIndex;
// view
late View studentGradeView;
late DateColumn studentJoinDate;
DbModel(Database db) : super(db);
@override
void defineDatabaseObjects(Database db) {
// Grade table
gradeName = db.stringColumn('gradeName', 50);
studentsCount = db.intColumn('studentsCount', defaultValue: 0);
gradesTable = db.newTable('Grades', [gradeName, studentsCount]);
// student table
studentName = db.stringColumn('studentName', 200);
studentDegree = db.intColumn('studentDegree', defaultValue: 0);
studentJoinDate = db.dateColumn('studentJoinDate', allowNull: true);
studentsTable = db.newTable("Students", [studentName, studentDegree, studentJoinDate]);
// foreign key
studentGradeFk = studentsTable.addFKto(gradesTable, "studentGradeFk");
// indices
gradeNameIndex = db.newIndex('grade_name_idx', gradesTable, [gradeName], unique: true);
studentNameIndex = db.newIndex('student_name_idx', studentsTable, [studentName]);
// view
studentGradeView = db.newView("student_grade_vw",
db.Select().From(studentsTable.InnerJoin(gradesTable, studentGradeFk.Equal(gradesTable.Id))));
}
@override
void defineSchemaUpdates(Database db) {
// db migrations go here, it only supports adding new db objects, else you'll have to write raw sql
db.addSchemaUpdate(SchemaUpdate(objects: [gradesTable, studentsTable]));
//
// you don't have to include table columns unless it's table is already created in older migration
db.addSchemaUpdate(SchemaUpdate(objects: [studentJoinDate]));
//
db.addSchemaUpdate(SchemaUpdate(objects: [gradeNameIndex, studentNameIndex, studentGradeView]));
}
}
2. 初始化数据库
初始化数据库可以使用文件存储或内存存储。这里以内存存储为例:
import 'dart:io' show Directory;
import 'package:path_provider/path_provider.dart';
import 'package:dart_data_source/dart_data_source.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> logList = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
Expanded(
child: ListView(
children: logList.map((e) => Text(e)).toList(),
),
),
TextButton(
child: Text('press'),
onPressed: () => _onBtnPress(),
),
],
),
),
),
);
}
_onBtnPress() async {
var db = new InMemoryDatabase();
var dbm = new DbModel(db);
var dbc = await db.newContext()
..setLogger(resultLogger: (log) => print(log), sqlLogger: (log) => print(log));
// 新建模式
await dbm.init(dbc);
var version = await db.currentVersion(dbc);
log('数据库版本 => $version');
expect(version, 3);
// 插入数据
await db.InsertInto(dbm.gradesTable)
.Values([dbm.gradeName.Assign('Grade1'), dbm.studentsCount.Assign(0)]).execute(dbc);
await db.InsertInto(dbm.gradesTable).ValuesMap({'gradeName': 'Grade2', 'studentsCount': 0}).execute(dbc);
await dbc.rawInsert("insert into Grades (gradeName, studentsCount) values ('Grade3', 0)");
var gradeCount = await db.Select()
.Fields([Expr.Count(dbm.gradesTable.Id)])
.From(dbm.gradesTable)
.executeScalar(dbc);
log('年级数量 => $gradeCount');
expect(gradeCount, 3);
var gradesData = await db.Select().From(dbm.gradesTable).execute(dbc);
log('年级数据 => $gradesData');
// 在事务中添加 30 名学生,并更新年级表中的学生数量
await dbc.executeTransaction((transactionContext) async {
for (int i = 1; i <= 10; i++) {
await db.InsertInto(dbm.studentsTable).ValuesMap({
'studentName': 'ahmed$i-1',
'studentDegree': i * 10,
'studentJoinDate': DateTime(2020, 1, i),
'studentSuccess': false,
'studentGradeFk': 1
}).execute(transactionContext);
}
//
for (int i = 1; i <= 10; i++) {
await db.InsertInto(dbm.studentsTable).ValuesMap({
'studentName': 'ahmed$i-2',
'studentDegree': i * 10,
'studentJoinDate': DateTime(2020, 1, i),
'studentSuccess': 1, // int value for bool
'studentGradeFk': 2
}).execute(transactionContext);
}
//
for (int i = 1; i <= 10; i++) {
db.InsertInto(dbm.studentsTable).ValuesMap({
'test': null, // this field shall be ignored
'studentName': 'ahmed$i-3',
'studentDegree': i * 10,
'studentJoinDate': DateTime(2020, 1, i),
'studentGradeFk': 3
}).execute(transactionContext);
}
//
await db.Update(dbm.gradesTable)
.Set([dbm.studentsCount.Assign(10)])
.Where(dbm.gradesTable.Id.InValues([1, 2, 3]))
.execute(transactionContext);
});
gradesData = await db.Select().From(dbm.gradesTable).execute(dbc);
log('年级数据 => $gradesData');
var studentsData = await db.Select().From(dbm.studentsTable).execute(dbc);
log('学生数据 => $studentsData');
expect(30, studentsData.length);
// 按日期查询
var q1 = await db.Select()
.From(dbm.studentsTable)
.Where(dbm.studentJoinDate.BetweenValues(DateTime(2020, 1, 2), DateTime(2020, 1, 6)))
.execute(dbc);
expect(15, q1.length);
log('学生日期从 2 到 6 => $q1');
// 删除年级
await db.DeleteFrom(dbm.gradesTable).Where(dbm.gradesTable.Id.Equal(3)).execute(dbc);
gradesData = await db.Select().From(dbm.gradesTable).execute(dbc);
expect(2, gradesData.length);
expect(20, (await db.Select().From(dbm.studentsTable).execute(dbc)).length);
// 联合查询
var q2 = await db.Select()
.From(dbm.studentsTable)
.Where(dbm.studentsTable.Id.GreaterThan(1))
.Intersect(db.Select().From(dbm.studentsTable).Where(dbm.studentsTable.Id.LessThan(3)))
.execute(dbc);
log('联合查询 => $q2');
expect(1, q2.length);
// 从视图查询
var q3 = await db.Select()
.From(dbm.studentGradeView)
.Where(dbm.studentJoinDate.Equal(DateTime(2020, 1, 5)))
.execute(dbc);
log('从视图查询 => $q3');
expect(2, q3.length);
var q4 = await db.Select().From(dbm.studentGradeView).Page(0, 2).execute(dbc);
log('从视图查询前两行 => $q4');
expect(2, q4.length);
var q5 = await db.Select().From(dbm.studentGradeView).Where(dbm.studentSuccess.Equal(true)).Page(0, 2).execute(dbc);
log('根据布尔字段查询前两行 => $q5');
expect(2, q5.length);
var q6 = await db.Select()
.From(dbm.studentsTable)
.Where(Expr.DateFormat(dbm.studentJoinDate, '%d').Equal('01'))
.execute(dbc);
log('使用日期格式查询 => $q6');
expect(2, q6.length);
dbc.close();
}
void expect(Object? a, Object? b) {
log('断言: $a = $b');
assert(a == b);
}
void log(String line) {
logList.add(line + '\n------');
setState(() {});
}
}
3. 执行 SQL 操作
插入数据
await db.InsertInto(dbm.gradesTable)
.Values([dbm.gradeName.Assign('Grade1'), dbm.studentsCount.Assign(0)]).execute(dbc);
await db.InsertInto(dbm.gradesTable).ValuesMap({'gradeName': 'Grade2', 'studentsCount': 0}).execute(dbc);
await dbc.rawInsert("insert into Grades (gradeName, studentsCount) values ('Grade3', 0)");
查询数据
var gradeCount = await db.Select()
.Fields([Expr.Count(dbm.gradesTable.Id)])
.From(dbm.gradesTable)
.executeScalar(dbc);
print('年级数量 => $gradeCount');
更新数据
await db.Update(dbm.gradesTable)
.Set([dbm.gradeName.Assign('First Grade')])
.Where(dbm.gradeName.Equal('Grade1'))
.execute(dbc);
删除数据
await db.DeleteFrom(dbm.gradesTable).Where(dbm.gradesTable.Id.Equal(1)).execute(dbc);
事务处理
await dbc.executeTransaction((transactionContext) async {
for (int i = 1; i <= 10; i++) {
await db.InsertInto(dbm.studentsTable).ValuesMap({
'studentName': 'student$i-grade1',
'studentDegree': i * 10,
'studentJoinDate': DateTime(2020, 1, i),
'studentGradeFk': 1
}).execute(transactionContext);
}
for (int i = 1; i <= 10; i++) {
await db.InsertInto(dbm.studentsTable).ValuesMap({
'studentName': 'student$i-grade2',
'studentDegree': i * 10,
'studentJoinDate': DateTime(2020, 1, i),
'studentGradeFk': 2
}).execute(transactionContext);
}
await db.Update(dbm.gradesTable)
.Set([dbm.studentsCount.Assign(dbm.studentsCount.PlusValue(10))])
.Where(dbm.gradesTable.Id.InValues([1, 2]))
.execute(transactionContext);
});
更多关于Flutter数据访问插件dart_data_source的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据访问插件dart_data_source的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
dart_data_source
是一个用于 Flutter 应用中的数据访问插件,它允许开发者方便地处理不同数据源(如 SQLite、网络请求等)的数据。它提供了一套统一的 API 来操作数据,并且支持类型安全的数据访问。
主要特点
- 统一的数据访问接口:无论数据源是 SQLite、REST API 还是其他,
dart_data_source
提供了一套统一的接口来访问和操作数据。 - 类型安全:通过泛型和强类型支持,减少了运行时错误。
- 数据绑定:支持将数据直接绑定到 Flutter 的 UI 组件上,简化了数据驱动的 UI 开发。
- 支持多种数据源:包括 SQLite、REST API 等。
基本使用
1. 安装
首先,在 pubspec.yaml
中添加 dart_data_source
依赖:
dependencies:
flutter:
sdk: flutter
dart_data_source: ^1.0.0
然后运行 flutter pub get
来安装依赖。
2. 配置数据源
假设你使用的是 SQLite 数据库,首先需要配置数据源:
import 'package:dart_data_source/dart_data_source.dart';
void main() {
var dataSource = SQLiteDataSource('my_database.db');
dataSource.open().then((_) {
// 数据源已打开,可以执行查询等操作
}).catchError((error) {
print('Failed to open data source: $error');
});
}
3. 定义数据模型
定义一个数据模型类来表示数据库中的表:
class User {
int id;
String name;
int age;
User({this.id, this.name, this.age});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'age': age,
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'],
name: map['name'],
age: map['age'],
);
}
}
4. 查询数据
使用 dart_data_source
查询数据:
Future<List<User>> getUsers(SQLiteDataSource dataSource) async {
var result = await dataSource.query('SELECT * FROM users');
return result.map((map) => User.fromMap(map)).toList();
}
5. 插入数据
插入新数据:
Future<void> insertUser(SQLiteDataSource dataSource, User user) async {
await dataSource.insert('users', user.toMap());
}
6. 更新数据
更新现有数据:
Future<void> updateUser(SQLiteDataSource dataSource, User user) async {
await dataSource.update('users', user.toMap(), where: 'id = ?', whereArgs: [user.id]);
}
7. 删除数据
删除数据:
Future<void> deleteUser(SQLiteDataSource dataSource, int userId) async {
await dataSource.delete('users', where: 'id = ?', whereArgs: [userId]);
}
数据绑定
dart_data_source
支持将数据绑定到 Flutter 的 UI 组件上。例如,你可以使用 FutureBuilder
或 StreamBuilder
来显示从数据源中获取的数据:
class UserList extends StatelessWidget {
final SQLiteDataSource dataSource;
UserList({this.dataSource});
[@override](/user/override)
Widget build(BuildContext context) {
return FutureBuilder<List<User>>(
future: getUsers(dataSource),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
var users = snapshot.data;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
var user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text('Age: ${user.age}'),
);
},
);
}
},
);
}
}