Flutter: moor_flutter庫,簡化sqlite操作


install

dependencies:
  ...
  moor_flutter:

dev_dependencies:
 ...
  moor_generator:
  build_runner:

lib\db\moor.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);
}

lib\store\main\main.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();

lib\main.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);
        },
      ),
    );
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM