install
dependencies:
...
moor_flutter:
dev_dependencies:
...
moor_generator:
build_runner:
libdbmoor.db.dart
import 'package:moor_flutter/moor_flutter.dart';
part 'moor.db.g.dart';
// 建表
class Tasks extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().withLength(min: 1, max: 50)();
DateTimeColumn get dueData => dateTime().nullable()();
BoolColumn get completed => boolean().withDefault(const Constant(false))();
}
@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,
DateTime dueData,
}) =>
into(tasks).insert(
TasksCompanion(
name: Value(name),
dueData: Value(dueData),
),
);
/// 更新一条数据
Future<bool> updateTask(Task task) => update(tasks).replace(task);
/// 删除一条数据
Future<int> deleteTask(Task task) => delete(tasks).delete(task);
}
libstoremainmain.store.dart
import 'package:flutter_moor_demo/db/moor.db.dart';
class MainStore {
final dbService = DBService();
}
class DBService {
final database = AppDatabase();
Stream<List<Task>> get tasks$ =>
database.watchAllTasks().map((List<Task> tasks) {
/// 排序,把完成的排在后面
tasks.sort(
(a, b) => _getInt(a.completed).compareTo(_getInt(b.completed)),
);
return tasks;
});
int _getInt(bool b) {
return b ? 1 : 0;
}
}
final MainStore mainStore = MainStore();
libmain.dart
import 'package:flutter/material.dart';
import 'package:flutter_moor_demo/store/main/main.store.dart';
import 'db/moor.db.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DateTime newTaskDate;
TextEditingController controller;
@override
void initState() {
super.initState();
controller = TextEditingController();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Tasks'),
),
body: Column(
children: <Widget>[
Expanded(
child: StreamBuilder<List<Task>>(
stream: mainStore.dbService.tasks$,
initialData: List<Task>(),
builder: (context, snap) {
if (snap.connectionState == ConnectionState.active) {
List<Task> tasks = snap.data;
if (tasks.isEmpty) return Center(child: Text('Not Data'));
return ListView.builder(
itemCount: tasks.length + 1,
itemBuilder: (context, int index) {
if (index == 0) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('taskS #${tasks.length}')),
);
}
final task = tasks[index - 1];
return Dismissible(
key: ValueKey(task.id),
background: Container(color: Colors.red),
onDismissed: (DismissDirection d) {
mainStore.dbService.database.deleteTask(task);
},
child: CheckboxListTile(
title: Text(task.name),
subtitle: Text(task.dueData?.toString() ?? 'No date'),
value: task.completed,
onChanged: (bool nv) {
mainStore.dbService.database
.updateTask(task.copyWith(completed: nv));
},
),
);
},
);
} else if (snap.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return SizedBox();
}
},
),
),
ListTile(
title: TextField(
controller: controller,
decoration: InputDecoration(hintText: 'Task Name'),
onSubmitted: (String v) {
mainStore.dbService.database.insertTask(
name: v.trim(),
dueData: newTaskDate,
);
_reset();
},
),
trailing: IconButton(
icon: Icon(Icons.calendar_today),
onPressed: () async {
DateTime now = DateTime.now();
Duration d = Duration(days: 10);
newTaskDate = await showDatePicker(
context: context,
initialDate: now,
firstDate: now.subtract(d),
lastDate: now.add(d));
},
),
)
],
),
);
}
void _reset() {
setState(() {
controller.clear();
newTaskDate = null;
});
}
}

moor_flutter迁移至moor_ffi
import 'dart:io';
import 'package:moor/moor.dart';
import 'package:moor_ffi/moor_ffi.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'tabel.g.dart';
// 这将为我们生成一个名为todos的表。 该表的行将
// 由称为Todo的类表示
class Todos extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()();
}
// 这将使moor生成一个名为"Category"的类来表示该表中的一行。
// 在表格名称中,默认情况下,将使用"Categorie",因为它只会去除结尾的"s"
@DataClassName("Category")
class Categories extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text()();
}
LazyDatabase _openConnection() {
// LazyDatabase实用程序使我们能够找到文件异步的正确位置。
return LazyDatabase(() async {
// 将数据库文件db.sqlite放入documents文件夹
// 为您的应用.
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
return VmDatabase(file);
});
}
// 此注释告诉moor准备使用两个
// 我们刚刚定义的表格。 稍后我们将介绍如何使用该数据库类
@UseMoor(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
// 我们通过这个构造函数告诉数据库在哪里存储数据
MyDatabase() : super(_openConnection());
// 您应该在更改或添加表定义时增加该数字
// 本自述文件稍后将介绍迁移
@override
int get schemaVersion => 1;
Stream<List<Todo>> allTodos() {
return (select(todos)).watch();
}
Future<int> add(Insertable<Todo> d) {
return into(todos).insert(d);
}
}
使用
import 'package:flutter/material.dart';
import 'package:flutter_demo/db/tabel.dart';
MyDatabase db;
void main() {
db = MyDatabase();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _id = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: StreamBuilder<List<Todo>>(
stream: db.allTodos(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting ||
!snapshot.hasData) return SizedBox();
return ListView(
children: snapshot.data.map((it) {
// 这里表的字段和上面定义的不一样
return ListTile(
key: ValueKey(it.id),
title: Text(it.title),
subtitle: Text(it.content),
);
}).toList(),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_id++;
});
// 插入新数据
var newTodo = TodosCompanion.insert(
title: '#$_id new title', content: '#$_id content');
db.add(newTodo);
},
),
);
}
}