【Flutter】sqfliteでデータを扱う

Flutter

sqfliteとは

sqfliteは、FlutterアプリケーションでSQLiteデータベースを利用するためのプラグインです。

  • トランザクションとバッチ処理のサポート
  • データベースの自動バージョン管理
  • 背景スレッドでのデータベース操作(iOSおよびAndroid)
  • Linux、Windows、Dart VM用のサポート(sqflite_common_ffiを使用)
  • 実験的なWebサポート(sqflite_common_ffi_webを使用)
sqflite | Flutter package
Flutter plugin for SQLite, a self-contained, high-reliability, embedded, SQL database engine.

使い方

インストール方法

  1. pubspec.yamlファイルに依存関係を追加します。
dependencies:
  sqflite: ^2.3.3+1

データベースのオープン

SQLiteデータベースはファイルシステム内のパスで識別されるファイルです。

var db = await openDatabase('my_db.db');

データベースのバージョン管理やスキーマ変更の処理を行うためのメカニズムも提供されています。

データベースのクローズ

アプリケーション終了時にリソースを解放するためにデータベースを閉じることができます。

await db.close();

基本的なクエリの実行

データベースの作成とテーブルの生成

var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');

await deleteDatabase(path);

Database database = await openDatabase(path, version: 1,
    onCreate: (Database db, int version) async {
  await db.execute(
      'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});

データの挿入

await database.transaction((txn) async {
  int id1 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
  print('inserted1: $id1');
  int id2 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES(?, ?, ?)',
      ['another name', 12345678, 3.1416]);
  print('inserted2: $id2');
});

データの更新

int count = await database.rawUpdate(
    'UPDATE Test SET name = ?, value = ? WHERE name = ?',
    ['updated name', '9876', 'some name']);
print('updated: $count');

データの取得

List<Map> list = await database.rawQuery('SELECT * FROM Test');
print(list);

データの削除

int count = await database.rawDelete('DELETE FROM Test WHERE name = ?', ['another name']);
print('deleted: $count');

トランザクションの利用

トランザクションを使用して一連の操作をまとめて実行し、一貫性を保つことができます。

await database.transaction((txn) async {
  await txn.execute('CREATE TABLE Test1 (id INTEGER PRIMARY KEY)');

  // データベースオブジェクトをトランザクション内で使用しない
  // デッドロックが発生する可能性あり
  await database.execute('CREATE TABLE Test2 (id INTEGER PRIMARY KEY)');
});

トランザクションはコールバックがエラーをスローしない限りコミットされます。エラーがスローされるとトランザクションはキャンセルされます。

バッチ処理

複数の操作を一度に実行することでパフォーマンスを向上させることができます。

var batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
var results = await batch.commit();

エラーが発生した場合でも続行したい場合は、以下のように設定します。

await batch.commit(continueOnError: true);

SQLヘルパーの利用

以下は、SQLヘルパークラスを使用した例です。

final String tableTodo = 'todo';
final String columnId = '_id';
final String columnTitle = 'title';
final String columnDone = 'done';

class Todo {
  int id;
  String title;
  bool done;

  Map<String, Object?> toMap() {
    var map = <String, Object?>{
      columnTitle: title,
      columnDone: done == true ? 1 : 0
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }

  Todo();

  Todo.fromMap(Map<String, Object?> map) {
    id = map[columnId];
    title = map[columnTitle];
    done = map[columnDone] == 1;
  }
}

class TodoProvider {
  Database db;

  Future open(String path) async {
    db = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('''
create table $tableTodo ( 
  $columnId integer primary key autoincrement, 
  $columnTitle text not null,
  $columnDone integer not null)
''');
    });
  }

  Future<Todo> insert(Todo todo) async {
    todo.id = await db.insert(tableTodo, todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    List<Map> maps = await db.query(tableTodo,
        columns: [columnId, columnDone, columnTitle],
        where: '$columnId = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }

  Future<int> delete(int id) async {
    return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]);
  }

  Future<int> update(Todo todo) async {
    return await db.update(tableTodo, todo.toMap(),
        where: '$columnId = ?', whereArgs: [todo.id]);
  }

  Future close() async => db.close();
}

このようにして、簡単にCRUD操作を行うことができます。

サポートされているSQLiteのデータ型

SQLiteでサポートされているデータ型について、以下の点に注意してください:

  • INTEGER: Dartのint
  • REAL: Dartのnum
  • TEXT: DartのString
  • BLOB: DartのUint8List

DateTimeboolは直接サポートされていないため、例えばDateTimeintmillisSinceEpoch)やString(ISO8601形式)として保存する必要があります。boolINTEGERとして保存し、0と1の値を使用します。

Buy me a coffee!

Flutterアプリ開発
シェアする
sogaをフォローする
タイトルとURLをコピーしました