2个数据库框架的简单入门。floor和 moor_flutter
moor由于moor_generator与众多其他库的generator不兼容,所以如果要使用的话,只能是通过其他工程生成code之后拷贝到当前工程中。如果路过的大神知道解决方案望不吝赐教。
1.floor
Flutter 应用的SQLite抽象支持。
Floor库提供了轻量的SQLite抽象,在内存对象与数据库之间自动映射,同时可通过SQL完全控制数据库。
需要注意的是,这个库并不像Hibernate那样是一个功能齐全的ORM,而且永远不会是。因此,不支持自动关系映射是有意的。
使用
1.导包
dependencies:
path: ^1.6.4
floor: ^0.11.0
dev_dependencies:
build_runner: ^1.7.4
floor_generator: ^0.11.0
2.定义table和dao
import 'package:floor/floor.dart';
@entity
class Work {
@primaryKey
final int id;
final String name;
@ColumnInfo(name: 'create_time', nullable: true)
final String createTime;
Work({this.id, this.name, this.createTime});
}
@dao
abstract class WorkDao {
@Query('SELECT * FROM Work')
Future<List<Work>> findAllWorks();
@Query('SELECT * FROM Work')
Stream<List<Work>> findAllWorksAsStream(); // stream return
@Query('SELECT * FROM Work WHERE id=:id')
Future<List<Work>> findWorkById(int id);
@insert
Future<void> insertWork(Work work);
@delete
Future<int> deleteWorks(List<Work> person);
@delete
Future<void> deleteWork(Work work);
}
3.定义database
import 'dart:async';
import 'package:floor/floor.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
import 'work.dart';
part 'work_db.g.dart';
@Database(version: 1,entities: [Work])
abstract class AppDatabase extends FloorDatabase{
WorkDao get workDao;
}
4.生成代码
运行flutter packages pub run build_runner build
5.定义
DBService
import 'package:floor/floor.dart';
import 'work.dart';
import 'work_db.dart';
final dbService = DBService();
class DBService {
Future<WorkDao> getWorkDao() async {
final dataBase = await $FloorAppDatabase
.databaseBuilder('work.db')
.addMigrations(<Migration>[
Migration(1, 3, (db) {
// db.execute('ALTER TABLE Work ADD COLUMN create_time TEXT');
}),
]).build();
return dataBase.workDao;
}
}
6.应用到页面
import 'package:flutter/material.dart';
import 'models/db_service.dart';
import 'models/work.dart';
class FloorTestPage extends StatefulWidget {
@override
_FloorTestPageState createState() => _FloorTestPageState();
}
class _FloorTestPageState extends State<FloorTestPage> {
final TextEditingController controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Floor 框架测试'),
),
body: Column(
children: <Widget>[
TextField(
controller: controller,
decoration: InputDecoration(hintText: '输入名称'),
onSubmitted: (v) {
getDao().then((dao) {
dao.insertWork(Work(
name: controller.text,
createTime: DateTime.now().toString().substring(0, 19)));
controller.clear();
});
},
),
FutureBuilder(
future: getDao(),
builder: (c, s) {
print('state ${s.connectionState}');
if (s.connectionState == ConnectionState.done) {
WorkDao dao = s.data;
return Expanded(
child: StreamBuilder(
stream: dao.findAllWorksAsStream(),
builder: (c, s) {
print('connection state:${s.connectionState}');
if (s.connectionState == ConnectionState.active) {
List<Work> works = s.data;
return ListView.builder(
itemCount: works.length,
itemBuilder: (c, i) {
Work work = works[i];
return Dismissible(
key: ValueKey(work.id),
background: Container(
color: Colors.red,
),
child: ListTile(
title: Text(work.name),
subtitle: Text(work.createTime ?? ''),
),
direction: DismissDirection.endToStart,
onDismissed: (DismissDirection direction) {
dao.deleteWork(work);
},
);
},
);
} else if (s.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Center(
child: Text('其他'),
);
}
},
initialData: [],
),
);
} else if (s.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Center(
child: Text('可能出错了'),
);
}
},
)
],
),
);
}
WorkDao _dao;
Future<WorkDao> getDao() async {
if (_dao == null) {
_dao = await dbService.getWorkDao();
}
return _dao;
}
}
2.moor_flutter
特性
- 1.灵活:
可以通过sql或dart实现数据库操作,为2中语言提供了流畅的API。可以过滤或排序结果或者使用joins
合并多表查询结果。甚至支持复杂的sql语句,如WITH
和WINDOW
- 2.功能丰富:
支持transactions
、schema
迁移(migration
),复杂的过滤与表达,批量升级和合并。我们甚至有SQL内置IDE。- 3.模块化:
得益于内置支持daos
操作和导入sql文件,可以保持你的数据库代码简洁- 4.安全:
Moor根据你的库表table
和查询语句queries
构建类型安全的代码,如果你的查询语句queries
有一个错误,moor会在编译时发现它并给你提供有帮助的描述提示。- 5.反应式:
sql语句可以转变为可自动更新的数据流stream
,包括多表复杂的查询语句- 6.跨平台支持:
支持Android,iOS,macOS,Windows,Linux,Web。示例- 测试与生产:
Moor是稳定的,且测试友好的,支持各种各样的单位和融合的测试。支持Flutter app.
使用
1.导包
dependencies:
moor_flutter: ^2.1.0
dev_dependencies:
build_runner: ^1.7.4
moor_generator: ^2.3.1
- 定义表
import 'package:moor_flutter/moor_flutter.dart';
//flutter packages pub run build_runner build
part 'task.g.dart';
class Tasks extends Table {
TextColumn get name => text()();
TextColumn get des => text()();
TextColumn get createTime => text().nullable()();
IntColumn get id => integer().autoIncrement()();
}
@UseMoor(tables: [Tasks])
class AppDataBase extends _$AppDataBase {
AppDataBase()
: super(FlutterQueryExecutor.inDatabaseFolder(path: 'db.sqlite'));
@override
int get schemaVersion =>1;
Future<List<Task>> get getAllTasks => select(tasks).get();
/// 每当基础数据发生变化时,都会发出新项
Stream<List<Task>> watchAllTasks() => select(tasks).watch();
/// 插入一条数据
Future<int> insertTask({
String name,
String des,
String createTime,
}) =>
into(tasks).insert(
TasksCompanion(
name: Value(name),
des: Value(des),
createTime: Value(createTime),
),
);
/// 更新一条数据
Future<bool> updateTask(Task task) => update(tasks).replace(task);
/// 删除一条数据
Future<int> deleteTask(Task task) => delete(tasks).delete(task);
@override
MigrationStrategy get migration => MigrationStrategy(
onCreate: (Migrator m){
print('create database:${m.toString()}');
return m.createAll();
},
onUpgrade: (Migrator m ,int from,int to)async{
//await m.addColumn(tasks, tasks.createTime);
},
beforeOpen: (details)async{
print('before:${details.versionBefore} now:${details.versionNow} wasCreated:${details.wasCreated} upgraded:${details.hadUpgrade}');
}
);
}
3.生成代码
运行flutter packages pub run build_runner build
4.使用
import 'task.dart';
class Store{
final dbService=DBService();
}
class DBService {
final database=AppDataBase();
Stream<List<Task>> get tasks=>
database?.watchAllTasks()?.map((List<Task> tasks){
// tasks.sort(
// (a,b)=>a.id-b.id
// );
return tasks;
});
}
final Store store=Store();
5.应用到页面
import 'package:flutter/material.dart';
import 'models/work.dart';
import 'models/store.dart';
class MoorTestPage extends StatefulWidget {
MoorTestPage({Key key, this.title}) : super(key: key);
final String title;
@override
_MoorTestPageState createState() => _MoorTestPageState();
}
class _MoorTestPageState extends State<MoorTestPage> {
int _counter = 0;
final TextEditingController controller = TextEditingController();
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextField(
controller: controller,
decoration: InputDecoration(hintText: '输入新任务名称'),
onSubmitted: (String v) {
store.dbService.database
.insertTask(name: v.trim(),des: 'des:$v',createTime: DateTime.now().toString().substring(0,'2020-02-02 00:00'.length))
.then((i) {
controller.clear();
});
},
),
),
],
),
Expanded(
child: StreamBuilder<List<Task>>(
initialData: [],
stream: store.dbService.tasks,
builder: (c, s) {
if (s.connectionState == ConnectionState.active) {
List<Task> tasks = s.data;
if (tasks.isEmpty)
return Center(
child: Text('Empty'),
);
return ListView.builder(
itemCount: tasks.length,
itemBuilder: (c, i) {
Task task = tasks[i];
return Dismissible(
key: ValueKey(task.id),
background: Container(
color: Colors.red,
),
onDismissed: (DismissDirection d) {
store.dbService.database.deleteTask(task);
},
child: CheckboxListTile(
title: Text(task.name),
subtitle: Text('${task.des} 创建时间:${task.createTime??''}'),
value: task.id % 2 == 0,
onChanged: (bool nv) {},
),
);
},
);
} else if (s.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return SizedBox();
}
},
),
)
],
),
),
);
}
}